Skip to content

Commit 639a595

Browse files
author
Alexander Zvegintsev
committed
8357584: [XWayland] [OL10] Robot.mousePress() is delivered to wrong place
Reviewed-by: lkostyra, arapte
1 parent 0270847 commit 639a595

File tree

12 files changed

+1173
-231
lines changed

12 files changed

+1173
-231
lines changed

modules/javafx.graphics/src/main/java/com/sun/glass/ui/gtk/GtkRobot.java

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
package com.sun.glass.ui.gtk;
2626

2727
import com.sun.glass.ui.gtk.screencast.ScreencastHelper;
28+
import com.sun.glass.ui.gtk.screencast.XdgDesktopPortal;
2829
import javafx.scene.input.KeyCode;
2930
import javafx.scene.input.MouseButton;
3031
import javafx.scene.paint.Color;
@@ -35,20 +36,6 @@
3536

3637
final class GtkRobot extends GlassRobot {
3738

38-
private static final String screenshotMethod;
39-
private static final String METHOD_GTK = "gtk";
40-
private static final String METHOD_SCREENCAST = "dbusScreencast";
41-
42-
static {
43-
String waylandDisplay = System.getenv("WAYLAND_DISPLAY");
44-
boolean isOnWayland = waylandDisplay != null && !waylandDisplay.isBlank();
45-
46-
String method =
47-
System.getProperty("javafx.robot.screenshotMethod",
48-
isOnWayland ? METHOD_SCREENCAST : METHOD_GTK);
49-
screenshotMethod = method;
50-
}
51-
5239
@Override
5340
public void create() {
5441
// no-op
@@ -62,15 +49,23 @@ public void destroy() {
6249
@Override
6350
public void keyPress(KeyCode code) {
6451
Application.checkEventThread();
65-
_keyPress(code.getCode());
52+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
53+
ScreencastHelper.remoteDesktopKey(true, code.getCode());
54+
} else {
55+
_keyPress(code.getCode());
56+
}
6657
}
6758

6859
protected native void _keyPress(int code);
6960

7061
@Override
7162
public void keyRelease(KeyCode code) {
7263
Application.checkEventThread();
73-
_keyRelease(code.getCode());
64+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
65+
ScreencastHelper.remoteDesktopKey(false, code.getCode());
66+
} else {
67+
_keyRelease(code.getCode());
68+
}
7469
}
7570

7671
protected native void _keyRelease(int code);
@@ -81,28 +76,45 @@ public void keyRelease(KeyCode code) {
8176
public void mouseMove(double x, double y) {
8277
Application.checkEventThread();
8378
_mouseMove((int) x, (int) y);
79+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
80+
// We still call _mouseMove on purpose to change the mouse position
81+
// within the XWayland server so that we can retrieve it later.
82+
ScreencastHelper.remoteDesktopMouseMove((int) x, (int) y);
83+
}
8484
}
8585

8686
@Override
8787
public void mousePress(MouseButton... buttons) {
8888
Application.checkEventThread();
89-
_mousePress(GlassRobot.convertToRobotMouseButton(buttons));
89+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
90+
ScreencastHelper.remoteDesktopMouseButton(true, GlassRobot.convertToRobotMouseButton(buttons));
91+
} else {
92+
_mousePress(GlassRobot.convertToRobotMouseButton(buttons));
93+
}
9094
}
9195

9296
protected native void _mousePress(int button);
9397

9498
@Override
9599
public void mouseRelease(MouseButton... buttons) {
96100
Application.checkEventThread();
97-
_mouseRelease(GlassRobot.convertToRobotMouseButton(buttons));
101+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
102+
ScreencastHelper.remoteDesktopMouseButton(false, GlassRobot.convertToRobotMouseButton(buttons));
103+
} else {
104+
_mouseRelease(GlassRobot.convertToRobotMouseButton(buttons));
105+
}
98106
}
99107

100108
protected native void _mouseRelease(int buttons);
101109

102110
@Override
103111
public void mouseWheel(int wheelAmt) {
104112
Application.checkEventThread();
105-
_mouseWheel(wheelAmt);
113+
if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) {
114+
ScreencastHelper.remoteDesktopMouseWheel(wheelAmt);
115+
} else {
116+
_mouseWheel(wheelAmt);
117+
}
106118
}
107119

108120
protected native void _mouseWheel(int wheelAmt);
@@ -130,7 +142,8 @@ public Color getPixelColor(double x, double y) {
130142
x = (int) Math.floor((x + 0.5) * mainScreen.getPlatformScaleX());
131143
y = (int) Math.floor((y + 0.5) * mainScreen.getPlatformScaleY());
132144
int[] result = new int[1];
133-
if (METHOD_SCREENCAST.equals(screenshotMethod)) {
145+
if ((XdgDesktopPortal.isScreencast()
146+
|| XdgDesktopPortal.isRemoteDesktop()) && ScreencastHelper.isAvailable()) {
134147
ScreencastHelper.getRGBPixels((int) x, (int) y, 1, 1, result);
135148
} else {
136149
_getScreenCapture((int) x, (int) y, 1, 1, result);
@@ -143,7 +156,8 @@ public Color getPixelColor(double x, double y) {
143156
@Override
144157
public void getScreenCapture(int x, int y, int width, int height, int[] data, boolean scaleToFit) {
145158
Application.checkEventThread();
146-
if (METHOD_SCREENCAST.equals(screenshotMethod)) {
159+
if ((XdgDesktopPortal.isScreencast()
160+
|| XdgDesktopPortal.isRemoteDesktop()) && ScreencastHelper.isAvailable()) {
147161
ScreencastHelper.getRGBPixels(x, y, width, height, data);
148162
} else {
149163
_getScreenCapture(x, y, width, height, data);

modules/javafx.graphics/src/main/java/com/sun/glass/ui/gtk/screencast/ScreencastHelper.java

Lines changed: 75 additions & 20 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
@@ -32,24 +32,27 @@
3232
import java.util.Set;
3333
import java.util.Timer;
3434
import java.util.TimerTask;
35+
import java.util.function.Function;
3536
import java.util.stream.IntStream;
36-
import java.util.function.Supplier;
3737

3838
/**
3939
* Helper class for grabbing pixels from the screen using the
4040
* <a href="https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.ScreenCast">
4141
* org.freedesktop.portal.ScreenCast API</a>
4242
*/
4343

44-
public class ScreencastHelper {
44+
public final class ScreencastHelper {
4545

4646
static final boolean SCREENCAST_DEBUG;
4747
private static final boolean IS_NATIVE_LOADED;
4848

49-
5049
private static final int ERROR = -1;
5150
private static final int DENIED = -11;
5251
private static final int OUT_OF_BOUNDS = -12;
52+
private static final int NO_STREAMS = -13;
53+
54+
private static final int XDG_METHOD_SCREENCAST = 0;
55+
private static final int XDG_METHOD_REMOTE_DESKTOP = 1;
5356

5457
private static final int DELAY_BEFORE_SESSION_CLOSE = 2000;
5558

@@ -58,26 +61,37 @@ public class ScreencastHelper {
5861
= new Timer("auto-close screencast session", true);
5962

6063

61-
private ScreencastHelper() {
62-
}
64+
private ScreencastHelper() {}
6365

6466
static {
65-
boolean isDebugEnabled =
66-
((Supplier<Boolean>) () -> {
67-
final String str =
68-
System.getProperty("javafx.robot.screenshotDebug", "false");
69-
return "true".equalsIgnoreCase(str);
70-
}).get();
71-
SCREENCAST_DEBUG = isDebugEnabled;
72-
73-
IS_NATIVE_LOADED = loadPipewire(SCREENCAST_DEBUG);
67+
SCREENCAST_DEBUG = Boolean.getBoolean("javafx.robot.screenshotDebug");
68+
69+
boolean loadFailed = false;
70+
71+
boolean shouldLoadNative = XdgDesktopPortal.isRemoteDesktop()
72+
|| XdgDesktopPortal.isScreencast();
73+
74+
int methodId = XdgDesktopPortal.isScreencast()
75+
? XDG_METHOD_SCREENCAST
76+
: XDG_METHOD_REMOTE_DESKTOP;
77+
78+
if (!(shouldLoadNative && loadPipewire(methodId, SCREENCAST_DEBUG))) {
79+
80+
System.err.println(
81+
"Could not load native libraries for ScreencastHelper"
82+
);
83+
84+
loadFailed = true;
85+
}
86+
87+
IS_NATIVE_LOADED = !loadFailed;
7488
}
7589

7690
public static boolean isAvailable() {
7791
return IS_NATIVE_LOADED;
7892
}
7993

80-
private static native boolean loadPipewire(boolean screencastDebug);
94+
private static native boolean loadPipewire(int method, boolean isDebug);
8195

8296
private static native int getRGBPixelsImpl(
8397
int x, int y, int width, int height,
@@ -196,21 +210,62 @@ public static synchronized void getRGBPixels(
196210
debugReturnValue(retVal);
197211
}
198212

199-
private static void debugReturnValue(int retVal) {
213+
private static boolean debugReturnValue(int retVal) {
200214
if (retVal == DENIED) {
201-
// user explicitly denied the capture, no more tries.
202215
if (SCREENCAST_DEBUG) {
203-
System.err.println("Screen Capture in the selected area was not allowed");
216+
System.err.println("robot action: access denied by user.");
204217
}
205218
} else if (retVal == ERROR) {
206219
if (SCREENCAST_DEBUG) {
207-
System.err.println("Screen capture failed.");
220+
System.err.println("robot action: failed.");
208221
}
209222
} else if (retVal == OUT_OF_BOUNDS) {
210223
if (SCREENCAST_DEBUG) {
211224
System.err.println(
212225
"Token does not provide access to requested area.");
213226
}
227+
} else if (retVal == NO_STREAMS) {
228+
if (SCREENCAST_DEBUG) {
229+
System.err.println("robot action: no streams available");
230+
}
214231
}
232+
return retVal != ERROR;
215233
}
234+
235+
private static void performWithToken(Function<String, Integer> func) {
236+
if (!XdgDesktopPortal.isRemoteDesktop() || !IS_NATIVE_LOADED) return;
237+
238+
timerCloseSessionRestart();
239+
240+
for (TokenItem tokenItem : TokenStorage.getTokens(getSystemScreensBounds())) {
241+
int retVal = func.apply(tokenItem.token);
242+
243+
if (retVal >= 0 || !debugReturnValue(retVal)) {
244+
return;
245+
}
246+
}
247+
248+
debugReturnValue(func.apply(null));
249+
}
250+
251+
public static synchronized void remoteDesktopMouseMove(int x, int y) {
252+
performWithToken((token) -> remoteDesktopMouseMoveImpl(x, y, token));
253+
}
254+
255+
public static synchronized void remoteDesktopMouseButton(boolean isPress, int buttons) {
256+
performWithToken((token) -> remoteDesktopMouseButtonImpl(isPress, buttons, token));
257+
}
258+
259+
public static synchronized void remoteDesktopMouseWheel(int wheel) {
260+
performWithToken((token) -> remoteDesktopMouseWheelImpl(wheel, token));
261+
}
262+
263+
public static synchronized void remoteDesktopKey(boolean isPress, int key) {
264+
performWithToken((token) -> remoteDesktopKeyImpl(isPress, key, token));
265+
}
266+
267+
private static synchronized native int remoteDesktopMouseMoveImpl(int x, int y, String token);
268+
private static synchronized native int remoteDesktopMouseButtonImpl(boolean isPress, int buttons, String token);
269+
private static synchronized native int remoteDesktopMouseWheelImpl(int wheelAmt, String token);
270+
private static synchronized native int remoteDesktopKeyImpl(boolean isPress, int key, String token);
216271
}

0 commit comments

Comments
 (0)