Skip to content

Commit 72d9bd6

Browse files
committed
8351907: [XWayland] [OL10] Robot.mousePress() is delivered to wrong place
Reviewed-by: mbaesken Backport-of: 2dfbf41d2a3dbcd44f9ed9a58a1b0932d7536977
1 parent 6d0a502 commit 72d9bd6

File tree

13 files changed

+886
-135
lines changed

13 files changed

+886
-135
lines changed

src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
import java.awt.image.WritableRaster;
5151
import java.io.BufferedReader;
5252
import java.io.IOException;
53-
import java.io.InputStreamReader;
5453
import java.security.AccessController;
5554
import java.security.PrivilegedAction;
5655
import java.util.Arrays;
@@ -280,14 +279,12 @@ public boolean shouldDisableSystemTray() {
280279
return result;
281280
}
282281

283-
private Integer getGnomeShellMajorVersion() {
282+
public Integer getGnomeShellMajorVersion() {
284283
try {
285284
Process process =
286285
new ProcessBuilder("/usr/bin/gnome-shell", "--version")
287286
.start();
288-
try (InputStreamReader isr = new InputStreamReader(process.getInputStream());
289-
BufferedReader reader = new BufferedReader(isr)) {
290-
287+
try (BufferedReader reader = process.inputReader()) {
291288
if (process.waitFor(2, SECONDS) && process.exitValue() == 0) {
292289
String line = reader.readLine();
293290
if (line != null) {

src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -36,15 +36,13 @@
3636
import sun.awt.X11GraphicsConfig;
3737
import sun.awt.X11GraphicsDevice;
3838
import sun.awt.screencast.ScreencastHelper;
39+
import sun.awt.screencast.XdgDesktopPortal;
3940
import sun.security.action.GetPropertyAction;
4041

4142
@SuppressWarnings("removal")
4243
final class XRobotPeer implements RobotPeer {
4344

4445
private static final boolean tryGtk;
45-
private static final String screenshotMethod;
46-
private static final String METHOD_X11 = "x11";
47-
private static final String METHOD_SCREENCAST = "dbusScreencast";
4846

4947
static {
5048
loadNativeLibraries();
@@ -54,20 +52,6 @@ final class XRobotPeer implements RobotPeer {
5452
new GetPropertyAction("awt.robot.gtk",
5553
"true")
5654
));
57-
58-
boolean isOnWayland = false;
59-
60-
if (Toolkit.getDefaultToolkit() instanceof SunToolkit sunToolkit) {
61-
isOnWayland = sunToolkit.isRunningOnWayland();
62-
}
63-
64-
screenshotMethod = AccessController.doPrivileged(
65-
new GetPropertyAction(
66-
"awt.robot.screenshotMethod",
67-
isOnWayland
68-
? METHOD_SCREENCAST
69-
: METHOD_X11
70-
));
7155
}
7256

7357
private static volatile boolean useGtk;
@@ -92,39 +76,63 @@ final class XRobotPeer implements RobotPeer {
9276
@Override
9377
public void mouseMove(int x, int y) {
9478
mouseMoveImpl(xgc, xgc.scaleUp(x), xgc.scaleUp(y));
79+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
80+
// We still call mouseMoveImpl on purpose to change the mouse position
81+
// within the XWayland server so that we can retrieve it later.
82+
ScreencastHelper.remoteDesktopMouseMove(xgc.scaleUp(x), xgc.scaleUp(y));
83+
}
9584
}
9685

9786
@Override
9887
public void mousePress(int buttons) {
99-
mousePressImpl(buttons);
88+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
89+
ScreencastHelper.remoteDesktopMouseButton(true, buttons);
90+
} else {
91+
mousePressImpl(buttons);
92+
}
10093
}
10194

10295
@Override
10396
public void mouseRelease(int buttons) {
104-
mouseReleaseImpl(buttons);
97+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
98+
ScreencastHelper.remoteDesktopMouseButton(false, buttons);
99+
} else {
100+
mouseReleaseImpl(buttons);
101+
}
105102
}
106103

107104
@Override
108105
public void mouseWheel(int wheelAmt) {
109-
mouseWheelImpl(wheelAmt);
106+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
107+
ScreencastHelper.remoteDesktopMouseWheel(wheelAmt);
108+
} else {
109+
mouseWheelImpl(wheelAmt);
110+
}
110111
}
111112

112113
@Override
113114
public void keyPress(int keycode) {
114-
keyPressImpl(keycode);
115+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
116+
ScreencastHelper.remoteDesktopKey(true, keycode);
117+
} else {
118+
keyPressImpl(keycode);
119+
}
115120
}
116121

117122
@Override
118123
public void keyRelease(int keycode) {
119-
keyReleaseImpl(keycode);
124+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
125+
ScreencastHelper.remoteDesktopKey(false, keycode);
126+
} else {
127+
keyReleaseImpl(keycode);
128+
}
120129
}
121130

122131
@Override
123132
public int getRGBPixel(int x, int y) {
124133
int[] pixelArray = new int[1];
125-
if (screenshotMethod.equals(METHOD_SCREENCAST)
126-
&& ScreencastHelper.isAvailable()) {
127-
134+
if ((XdgDesktopPortal.isScreencast()
135+
|| XdgDesktopPortal.isRemoteDesktop()) && ScreencastHelper.isAvailable()) {
128136
ScreencastHelper.getRGBPixels(x, y, 1, 1, pixelArray);
129137
} else {
130138
getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray, useGtk);
@@ -135,8 +143,8 @@ public int getRGBPixel(int x, int y) {
135143
@Override
136144
public int[] getRGBPixels(Rectangle bounds) {
137145
int[] pixelArray = new int[bounds.width * bounds.height];
138-
if (screenshotMethod.equals(METHOD_SCREENCAST)
139-
&& ScreencastHelper.isAvailable()) {
146+
if ((XdgDesktopPortal.isScreencast()
147+
|| XdgDesktopPortal.isRemoteDesktop()) && ScreencastHelper.isAvailable()) {
140148

141149
ScreencastHelper.getRGBPixels(bounds.x, bounds.y,
142150
bounds.width, bounds.height,

src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -142,6 +142,8 @@
142142
import sun.awt.X11GraphicsEnvironment;
143143
import sun.awt.XSettings;
144144
import sun.awt.datatransfer.DataTransferer;
145+
import sun.awt.screencast.ScreencastHelper;
146+
import sun.awt.screencast.XdgDesktopPortal;
145147
import sun.awt.util.PerformanceLogger;
146148
import sun.awt.util.ThreadGroupUtils;
147149
import sun.font.FontConfigManager;
@@ -1565,16 +1567,21 @@ public int getNumberOfButtons(){
15651567
awtLock();
15661568
try {
15671569
if (numberOfButtons == 0) {
1568-
numberOfButtons = getNumberOfButtonsImpl();
1569-
numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons;
1570-
//4th and 5th buttons are for wheel and shouldn't be reported as buttons.
1571-
//If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
1572-
//If we have 3 physical buttons and a wheel, we report 3 buttons.
1573-
//If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
1574-
if (numberOfButtons >=5) {
1575-
numberOfButtons -= 2;
1576-
} else if (numberOfButtons == 4 || numberOfButtons ==5){
1570+
if (XdgDesktopPortal.isRemoteDesktop()
1571+
&& ScreencastHelper.isAvailable()) {
15771572
numberOfButtons = 3;
1573+
} else {
1574+
numberOfButtons = getNumberOfButtonsImpl();
1575+
numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons;
1576+
//4th and 5th buttons are for wheel and shouldn't be reported as buttons.
1577+
//If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
1578+
//If we have 3 physical buttons and a wheel, we report 3 buttons.
1579+
//If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
1580+
if (numberOfButtons >= 5) {
1581+
numberOfButtons -= 2;
1582+
} else if (numberOfButtons == 4 || numberOfButtons == 5) {
1583+
numberOfButtons = 3;
1584+
}
15781585
}
15791586
}
15801587
//Assume don't have to re-query the number again and again.

src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@
4040
import java.util.Set;
4141
import java.util.Timer;
4242
import java.util.TimerTask;
43+
import java.util.function.Function;
4344
import java.util.stream.IntStream;
4445

4546
/**
@@ -54,10 +55,13 @@ public class ScreencastHelper {
5455
static final boolean SCREENCAST_DEBUG;
5556
private static final boolean IS_NATIVE_LOADED;
5657

57-
5858
private static final int ERROR = -1;
5959
private static final int DENIED = -11;
6060
private static final int OUT_OF_BOUNDS = -12;
61+
private static final int NO_STREAMS = -13;
62+
63+
private static final int XDG_METHOD_SCREENCAST = 0;
64+
private static final int XDG_METHOD_REMOTE_DESKTOP = 1;
6165

6266
private static final int DELAY_BEFORE_SESSION_CLOSE = 2000;
6367

@@ -66,8 +70,7 @@ public class ScreencastHelper {
6670
= new Timer("auto-close screencast session", true);
6771

6872

69-
private ScreencastHelper() {
70-
}
73+
private ScreencastHelper() {}
7174

7275
static {
7376
SCREENCAST_DEBUG = Boolean.parseBoolean(
@@ -80,9 +83,16 @@ private ScreencastHelper() {
8083

8184
boolean loadFailed = false;
8285

86+
boolean shouldLoadNative = XdgDesktopPortal.isRemoteDesktop()
87+
|| XdgDesktopPortal.isScreencast();
88+
89+
int methodId = XdgDesktopPortal.isScreencast()
90+
? XDG_METHOD_SCREENCAST
91+
: XDG_METHOD_REMOTE_DESKTOP;
92+
8393
if (!(Toolkit.getDefaultToolkit() instanceof UNIXToolkit tk
8494
&& tk.loadGTK())
85-
|| !loadPipewire(SCREENCAST_DEBUG)) {
95+
|| !(shouldLoadNative && loadPipewire(methodId, SCREENCAST_DEBUG))) {
8696

8797
System.err.println(
8898
"Could not load native libraries for ScreencastHelper"
@@ -98,7 +108,7 @@ public static boolean isAvailable() {
98108
return IS_NATIVE_LOADED;
99109
}
100110

101-
private static native boolean loadPipewire(boolean screencastDebug);
111+
private static native boolean loadPipewire(int method, boolean isDebug);
102112

103113
private static native int getRGBPixelsImpl(
104114
int x, int y, int width, int height,
@@ -195,7 +205,7 @@ public static synchronized void getRGBPixels(
195205

196206
if (retVal >= 0) { // we have received a screen data
197207
return;
198-
} else if (!checkReturnValue(retVal)) {
208+
} else if (!checkReturnValue(retVal, true)) {
199209
return;
200210
} // else, try other tokens
201211
}
@@ -209,25 +219,72 @@ public static synchronized void getRGBPixels(
209219
null
210220
);
211221

212-
checkReturnValue(retVal);
222+
checkReturnValue(retVal, true);
213223
}
214224

215-
private static boolean checkReturnValue(int retVal) {
225+
private static boolean checkReturnValue(int retVal,
226+
boolean throwException) {
216227
if (retVal == DENIED) {
217-
// user explicitly denied the capture, no more tries.
218-
throw new SecurityException(
219-
"Screen Capture in the selected area was not allowed"
220-
);
228+
if (SCREENCAST_DEBUG) {
229+
System.err.println("robot action: access denied by user.");
230+
}
231+
if (throwException) {
232+
// user explicitly denied the capture, no more tries.
233+
throw new SecurityException(
234+
"Screen Capture in the selected area was not allowed"
235+
);
236+
}
221237
} else if (retVal == ERROR) {
222238
if (SCREENCAST_DEBUG) {
223-
System.err.println("Screen capture failed.");
239+
System.err.println("robot action: failed.");
224240
}
225241
} else if (retVal == OUT_OF_BOUNDS) {
226242
if (SCREENCAST_DEBUG) {
227243
System.err.println(
228244
"Token does not provide access to requested area.");
229245
}
246+
} else if (retVal == NO_STREAMS) {
247+
if (SCREENCAST_DEBUG) {
248+
System.err.println("robot action: no streams available");
249+
}
230250
}
231251
return retVal != ERROR;
232252
}
253+
254+
private static void performWithToken(Function<String, Integer> func) {
255+
if (!XdgDesktopPortal.isRemoteDesktop() || !IS_NATIVE_LOADED) return;
256+
257+
timerCloseSessionRestart();
258+
259+
for (TokenItem tokenItem : TokenStorage.getTokens(getSystemScreensBounds())) {
260+
int retVal = func.apply(tokenItem.token);
261+
262+
if (retVal >= 0 || !checkReturnValue(retVal, false)) {
263+
return;
264+
}
265+
}
266+
267+
checkReturnValue(func.apply(null), false);
268+
}
269+
270+
public static synchronized void remoteDesktopMouseMove(int x, int y) {
271+
performWithToken((token) -> remoteDesktopMouseMoveImpl(x, y, token));
272+
}
273+
274+
public static synchronized void remoteDesktopMouseButton(boolean isPress, int buttons) {
275+
performWithToken((token) -> remoteDesktopMouseButtonImpl(isPress, buttons, token));
276+
}
277+
278+
public static synchronized void remoteDesktopMouseWheel(int wheel) {
279+
performWithToken((token) -> remoteDesktopMouseWheelImpl(wheel, token));
280+
}
281+
282+
public static synchronized void remoteDesktopKey(boolean isPress, int key) {
283+
performWithToken((token) -> remoteDesktopKeyImpl(isPress, key, token));
284+
}
285+
286+
private static synchronized native int remoteDesktopMouseMoveImpl(int x, int y, String token);
287+
private static synchronized native int remoteDesktopMouseButtonImpl(boolean isPress, int buttons, String token);
288+
private static synchronized native int remoteDesktopMouseWheelImpl(int wheelAmt, String token);
289+
private static synchronized native int remoteDesktopKeyImpl(boolean isPress, int key, String token);
233290
}

src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -69,6 +69,9 @@ private TokenStorage() {}
6969
private static final String REL_NAME_SECONDARY =
7070
".awt/robot/screencast-tokens.properties";
7171

72+
private static final String REL_RD_NAME =
73+
".java/robot/remote-desktop-tokens.properties";
74+
7275
private static final Properties PROPS = new Properties();
7376
private static final Path PROPS_PATH;
7477
private static final Path PROP_FILENAME;
@@ -107,11 +110,18 @@ private static Path setupPath() {
107110
return null;
108111
}
109112

110-
Path path = Path.of(userHome, REL_NAME);
111-
Path secondaryPath = Path.of(userHome, REL_NAME_SECONDARY);
113+
Path path;
114+
Path secondaryPath = null;
115+
116+
if (XdgDesktopPortal.isRemoteDesktop()) {
117+
path = Path.of(userHome, REL_RD_NAME);
118+
} else {
119+
path = Path.of(userHome, REL_NAME);
120+
secondaryPath = Path.of(userHome, REL_NAME_SECONDARY);
121+
}
112122

113123
boolean copyFromSecondary = !Files.isWritable(path)
114-
&& Files.isWritable(secondaryPath);
124+
&& secondaryPath != null && Files.isWritable(secondaryPath);
115125

116126
Path workdir = path.getParent();
117127

0 commit comments

Comments
 (0)