Skip to content

Commit 30b0c2a

Browse files
committedJun 26, 2024·
initial fix
1 parent 96f5023 commit 30b0c2a

File tree

9 files changed

+108
-100
lines changed

9 files changed

+108
-100
lines changed
 

‎buildSrc/linux.gradle

+5-4
Original file line numberDiff line numberDiff line change
@@ -89,21 +89,22 @@ setupTools("linux_gtk3",
8989
{ propFile ->
9090
ByteArrayOutputStream results2 = new ByteArrayOutputStream();
9191
exec {
92-
commandLine("${toolchainDir}pkg-config", "--cflags", "gtk+-3.0", "gthread-2.0", "xtst")
92+
commandLine("${toolchainDir}pkg-config", "--cflags", "gtk+-3.0", "gthread-2.0", "xtst", "gio-unix-2.0")
9393
setStandardOutput(results2);
9494
}
9595
propFile << "cflagsGTK3=" << results2.toString().trim() << "\n";
9696

9797
ByteArrayOutputStream results4 = new ByteArrayOutputStream();
9898
exec {
99-
commandLine("${toolchainDir}pkg-config", "--libs", "gtk+-3.0", "gthread-2.0", "xtst")
99+
commandLine("${toolchainDir}pkg-config", "--libs", "gtk+-3.0", "gthread-2.0", "xtst", "gio-unix-2.0")
100100
setStandardOutput(results4);
101101
}
102102
propFile << "libsGTK3=" << results4.toString().trim() << "\n";
103103

104104
},
105105
{ properties ->
106-
def cflagsGTK3 = properties.getProperty("cflagsGTK3")
106+
def cflagsGTK3 = properties.getProperty("cflagsGTK3") \
107+
+ " -I${project(":graphics").projectDir}/src/main/native-glass/gtk/libpipewire/include"
107108
def libsGTK3 = properties.getProperty("libsGTK3")
108109
if (cflagsGTK3 && libsGTK3) {
109110
gtk3CCFlags.addAll(cflagsGTK3.split(" "))
@@ -172,7 +173,7 @@ setupTools("linux_freetype_tools",
172173
freetypeLinkFlags.addAll(libs.split(" "))
173174
}
174175
} else {
175-
throw new IllegalStateException("Linux freetype packages not found.\nIf freetype pacakges are installed, please remove the build directory and try again.")
176+
throw new IllegalStateException("Linux freetype packages not found.\nIf freetype packages are installed, please remove the build directory and try again.")
176177
}
177178
}
178179
)

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

+29-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package com.sun.glass.ui.gtk;
2626

27+
import com.sun.glass.ui.gtk.screencast.ScreencastHelper;
2728
import javafx.scene.input.KeyCode;
2829
import javafx.scene.input.MouseButton;
2930
import javafx.scene.paint.Color;
@@ -32,8 +33,26 @@
3233
import com.sun.glass.ui.GlassRobot;
3334
import com.sun.glass.ui.Screen;
3435

36+
import java.security.AccessController;
37+
import java.security.PrivilegedAction;
38+
39+
@SuppressWarnings("removal")
3540
final class GtkRobot extends GlassRobot {
3641

42+
private static final String screenshotMethod;
43+
private static final String METHOD_GTK = "gtk";
44+
private static final String METHOD_SCREENCAST = "dbusScreencast";
45+
46+
static {
47+
boolean isOnWayland = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> {
48+
String waylandDisplay = System.getenv("WAYLAND_DISPLAY");
49+
return waylandDisplay != null && !waylandDisplay.isBlank();
50+
});
51+
52+
screenshotMethod = AccessController.doPrivileged((PrivilegedAction<String>) () ->
53+
System.getProperty("fx.robot.screenshotMethod", isOnWayland ? METHOD_SCREENCAST : METHOD_GTK));
54+
}
55+
3756
@Override
3857
public void create() {
3958
// no-op
@@ -115,7 +134,11 @@ public Color getPixelColor(double x, double y) {
115134
x = (int) Math.floor((x + 0.5) * mainScreen.getPlatformScaleX());
116135
y = (int) Math.floor((y + 0.5) * mainScreen.getPlatformScaleY());
117136
int[] result = new int[1];
118-
_getScreenCapture((int) x, (int) y, 1, 1, result);
137+
if (METHOD_SCREENCAST.equals(screenshotMethod)) {
138+
ScreencastHelper.getRGBPixels((int) x, (int) y, 1, 1, result);
139+
} else {
140+
_getScreenCapture((int) x, (int) y, 1, 1, result);
141+
}
119142
return GlassRobot.convertFromIntArgb(result[0]);
120143
}
121144

@@ -124,6 +147,10 @@ public Color getPixelColor(double x, double y) {
124147
@Override
125148
public void getScreenCapture(int x, int y, int width, int height, int[] data, boolean scaleToFit) {
126149
Application.checkEventThread();
127-
_getScreenCapture(x, y, width, height, data);
150+
if (METHOD_SCREENCAST.equals(screenshotMethod)) {
151+
ScreencastHelper.getRGBPixels(x, y, width, height, data);
152+
} else {
153+
_getScreenCapture(x, y, width, height, data);
154+
}
128155
}
129156
}

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

+32-48
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,13 @@
2323
* questions.
2424
*/
2525

26-
package sun.awt.screencast;
26+
package com.sun.glass.ui.gtk.screencast;
2727

28-
import sun.awt.UNIXToolkit;
29-
import sun.java2d.pipe.Region;
30-
import sun.security.action.GetPropertyAction;
28+
import com.sun.glass.ui.Screen;
3129

32-
import java.awt.GraphicsConfiguration;
33-
import java.awt.GraphicsEnvironment;
3430
import java.awt.Rectangle;
35-
import java.awt.Toolkit;
36-
import java.awt.geom.AffineTransform;
3731
import java.security.AccessController;
38-
import java.util.Arrays;
32+
import java.security.PrivilegedAction;
3933
import java.util.List;
4034
import java.util.Set;
4135
import java.util.Timer;
@@ -70,28 +64,14 @@ private ScreencastHelper() {
7064
}
7165

7266
static {
73-
SCREENCAST_DEBUG = Boolean.parseBoolean(
74-
AccessController.doPrivileged(
75-
new GetPropertyAction(
76-
"awt.robot.screenshotDebug",
77-
"false"
78-
)
79-
));
80-
81-
boolean loadFailed = false;
82-
83-
if (!(Toolkit.getDefaultToolkit() instanceof UNIXToolkit tk
84-
&& tk.loadGTK())
85-
|| !loadPipewire(SCREENCAST_DEBUG)) {
86-
87-
System.err.println(
88-
"Could not load native libraries for ScreencastHelper"
89-
);
90-
91-
loadFailed = true;
92-
}
93-
94-
IS_NATIVE_LOADED = !loadFailed;
67+
SCREENCAST_DEBUG =
68+
AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> {
69+
final String str =
70+
System.getProperty("fx.robot.screenshotDebug", "false");
71+
return "true".equalsIgnoreCase(str);
72+
});
73+
74+
IS_NATIVE_LOADED = loadPipewire(SCREENCAST_DEBUG);
9575
}
9676

9777
public static boolean isAvailable() {
@@ -107,24 +87,28 @@ private static native int getRGBPixelsImpl(
10787
String token
10888
);
10989

90+
//TODO copy from sun.java2d.pipe.Region.clipRound
91+
public static int clipRound(final double coordinate) {
92+
final double newv = coordinate - 0.5;
93+
if (newv < Integer.MIN_VALUE) {
94+
return Integer.MIN_VALUE;
95+
}
96+
if (newv > Integer.MAX_VALUE) {
97+
return Integer.MAX_VALUE;
98+
}
99+
return (int) Math.ceil(newv);
100+
}
101+
110102
private static List<Rectangle> getSystemScreensBounds() {
111-
return Arrays
112-
.stream(GraphicsEnvironment
113-
.getLocalGraphicsEnvironment()
114-
.getScreenDevices())
115-
.map(graphicsDevice -> {
116-
GraphicsConfiguration gc =
117-
graphicsDevice.getDefaultConfiguration();
118-
Rectangle screen = gc.getBounds();
119-
AffineTransform tx = gc.getDefaultTransform();
120-
121-
return new Rectangle(
122-
Region.clipRound(screen.x * tx.getScaleX()),
123-
Region.clipRound(screen.y * tx.getScaleY()),
124-
Region.clipRound(screen.width * tx.getScaleX()),
125-
Region.clipRound(screen.height * tx.getScaleY())
126-
);
127-
})
103+
return Screen
104+
.getScreens()
105+
.stream()
106+
.map(screen -> new Rectangle( //TODO should we get rid of AWT Rectangle?
107+
clipRound(screen.getPlatformX() * screen.getPlatformScaleX()),
108+
clipRound(screen.getPlatformY() * screen.getPlatformScaleY()),
109+
clipRound(screen.getPlatformWidth() * screen.getPlatformScaleX()),
110+
clipRound(screen.getPlatformHeight() * screen.getPlatformScaleY())
111+
))
128112
.toList();
129113
}
130114

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* questions.
2424
*/
2525

26-
package sun.awt.screencast;
26+
package com.sun.glass.ui.gtk.screencast;
2727

2828
import java.awt.Dimension;
2929
import java.awt.Rectangle;
@@ -33,7 +33,8 @@
3333
import java.util.stream.Collectors;
3434
import java.util.stream.IntStream;
3535

36-
import static sun.awt.screencast.ScreencastHelper.SCREENCAST_DEBUG;
36+
import static com.sun.glass.ui.gtk.screencast.ScreencastHelper.SCREENCAST_DEBUG;
37+
3738

3839
/**
3940
* Helper class used by {@link TokenStorage} as restore token record

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* questions.
2424
*/
2525

26-
package sun.awt.screencast;
26+
package com.sun.glass.ui.gtk.screencast;
2727

2828
import java.awt.Dimension;
2929
import java.awt.Rectangle;
@@ -51,7 +51,7 @@
5151
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
5252
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
5353
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
54-
import static sun.awt.screencast.ScreencastHelper.SCREENCAST_DEBUG;
54+
import static com.sun.glass.ui.gtk.screencast.ScreencastHelper.SCREENCAST_DEBUG;
5555

5656
/**
5757
* Helper class for persistent storage of ScreenCast restore tokens
@@ -66,7 +66,7 @@ final class TokenStorage {
6666
private TokenStorage() {}
6767

6868
private static final String REL_NAME =
69-
".awt/robot/screencast-tokens.properties";
69+
".fx/robot/screencast-tokens.properties";
7070

7171
private static final Properties PROPS = new Properties();
7272
private static final Path PROPS_PATH;

‎modules/javafx.graphics/src/main/native-glass/gtk/screencast_pipewire.c

+13-23
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,11 @@
2828
#endif
2929

3030
#include <dlfcn.h>
31-
#include "jni_util.h"
32-
#include "awt.h"
3331
#include "screencast_pipewire.h"
3432
#include "fp_pipewire.h"
3533
#include <stdio.h>
3634

37-
#include "gtk_interface.h"
38-
#include "gtk3_interface.h"
35+
extern JNIEnv* mainEnv;
3936

4037
int DEBUG_SCREENCAST_ENABLED = FALSE;
4138

@@ -675,7 +672,6 @@ static gboolean isAllDataReady() {
675672

676673

677674
static void *pipewire_libhandle = NULL;
678-
//glib_version_2_68 false for gtk2, as it comes from gtk3_interface.c
679675

680676
extern gboolean glib_version_2_68;
681677

@@ -689,13 +685,7 @@ extern gboolean glib_version_2_68;
689685
} while(0);
690686

691687
static gboolean loadSymbols() {
692-
if (!glib_version_2_68) {
693-
DEBUG_SCREENCAST("glib version 2.68+ required\n", NULL);
694-
return FALSE;
695-
}
696-
697-
pipewire_libhandle = dlopen(VERSIONED_JNI_LIB_NAME("pipewire-0.3", "0"),
698-
RTLD_LAZY | RTLD_LOCAL);
688+
pipewire_libhandle = dlopen("libpipewire-0.3.so.0", RTLD_LAZY | RTLD_LOCAL);
699689

700690
if (!pipewire_libhandle) {
701691
DEBUG_SCREENCAST("could not load pipewire library\n", NULL);
@@ -738,7 +728,8 @@ static gboolean loadSymbols() {
738728

739729
void storeRestoreToken(const gchar* oldToken, const gchar* newToken) {
740730

741-
JNIEnv* env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
731+
JNIEnv* env = mainEnv;
732+
742733
DEBUG_SCREENCAST("saving token, old: |%s| > new: |%s|\n", oldToken, newToken);
743734
if (env) {
744735
jstring jOldToken = NULL;
@@ -793,11 +784,11 @@ void storeRestoreToken(const gchar* oldToken, const gchar* newToken) {
793784
}
794785

795786
/*
796-
* Class: sun_awt_UNIXToolkit
797-
* Method: load_gtk
798-
* Signature: (IZ)Z
787+
* Class: com_sun_glass_ui_gtk_screencast_ScreencastHelper
788+
* Method: loadPipewire
789+
* Signature: (Z)Z
799790
*/
800-
JNIEXPORT jboolean JNICALL Java_sun_awt_screencast_ScreencastHelper_loadPipewire(
791+
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_screencast_ScreencastHelper_loadPipewire(
801792
JNIEnv *env, jclass cls, jboolean screencastDebug
802793
) {
803794
DEBUG_SCREENCAST_ENABLED = screencastDebug;
@@ -806,7 +797,7 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_screencast_ScreencastHelper_loadPipewire
806797
return JNI_FALSE;
807798
}
808799

809-
tokenStorageClass = (*env)->FindClass(env, "sun/awt/screencast/TokenStorage");
800+
tokenStorageClass = (*env)->FindClass(env, "com/sun/glass/ui/gtk/screencast/TokenStorage");
810801
if (!tokenStorageClass) {
811802
return JNI_FALSE;
812803
}
@@ -896,22 +887,21 @@ static int makeScreencast(
896887
}
897888

898889
/*
899-
* Class: sun_awt_screencast_ScreencastHelper
890+
* Class: com_sun_glass_ui_gtk_screencast_ScreencastHelper
900891
* Method: closeSession
901892
* Signature: ()V
902893
*/
903-
JNIEXPORT void JNICALL
904-
Java_sun_awt_screencast_ScreencastHelper_closeSession(JNIEnv *env, jclass cls) {
894+
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_screencast_ScreencastHelper_closeSession(JNIEnv *env, jclass cls) {
905895
DEBUG_SCREENCAST("closing screencast session\n\n", NULL);
906896
doCleanup();
907897
}
908898

909899
/*
910-
* Class: sun_awt_screencast_ScreencastHelper
900+
* Class: com_sun_glass_ui_gtk_screencast_ScreencastHelper
911901
* Method: getRGBPixelsImpl
912902
* Signature: (IIII[I[ILjava/lang/String;)I
913903
*/
914-
JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl(
904+
JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_screencast_ScreencastHelper_getRGBPixelsImpl(
915905
JNIEnv *env,
916906
jclass cls,
917907
jint jx,

‎modules/javafx.graphics/src/main/native-glass/gtk/screencast_pipewire.h

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#ifndef _SCREENCAST_PIPEWIRE_H
3232
#define _SCREENCAST_PIPEWIRE_H
3333

34+
#include <jni.h>
35+
3436
#include "screencast_portal.h"
3537

3638
#include <pipewire/stream.h>

‎modules/javafx.graphics/src/main/native-glass/gtk/screencast_portal.c

+15-15
Original file line numberDiff line numberDiff line change
@@ -219,16 +219,19 @@ gboolean initXdgDesktopPortal() {
219219
return FALSE;
220220
}
221221

222-
const gchar *name = gtk
223-
->g_dbus_connection_get_unique_name(portal->connection);
222+
const gchar *name = g_dbus_connection_get_unique_name(portal->connection);
224223
if (!name) {
225224
ERR("Failed to get unique connection name\n");
226225
return FALSE;
227226
}
228227

229228
GString * nameStr = g_string_new(name);
230-
g_string_erase(nameStr, 0, 1); //remove leading colon ":"
231-
g_string_replace(nameStr, ".", "_", 0);
229+
g_string_erase(nameStr, 0, 1); // remove leading colon ":"
230+
for (gsize i = 0; i < nameStr->len; ++i) { // replace '.' with '_'
231+
if (nameStr->str[i] == '.') {
232+
nameStr->str[i] = '_';
233+
}
234+
}
232235
portal->senderName = nameStr->str;
233236

234237
g_string_free(nameStr, FALSE);
@@ -362,6 +365,7 @@ static void callbackScreenCastCreateSession(
362365
}
363366

364367
helper->isDone = TRUE;
368+
gtk_main_quit();
365369
}
366370

367371
gboolean portalScreenCastCreateSession() {
@@ -426,9 +430,7 @@ gboolean portalScreenCastCreateSession() {
426430
err->message);
427431
ERR_HANDLE(err);
428432
} else {
429-
while (!helper.isDone) {
430-
g_main_context_iteration(NULL, TRUE);
431-
}
433+
gtk_main();
432434
}
433435

434436
unregisterScreenCastCallback(&helper);
@@ -472,6 +474,7 @@ static void callbackScreenCastSelectSources(
472474
if (result) {
473475
g_variant_unref(result);
474476
}
477+
gtk_main_quit();
475478
}
476479

477480
gboolean portalScreenCastSelectSources(const gchar *token) {
@@ -552,9 +555,7 @@ gboolean portalScreenCastSelectSources(const gchar *token) {
552555
DEBUG_SCREENCAST("Failed to call SelectSources: %s\n", err->message);
553556
ERR_HANDLE(err);
554557
} else {
555-
while (!helper.isDone) {
556-
g_main_context_iteration(NULL, TRUE);
557-
}
558+
gtk_main();
558559
}
559560

560561
unregisterScreenCastCallback(&helper);
@@ -625,8 +626,7 @@ static void callbackScreenCastStart(
625626

626627
if (restoreTokenVar) {
627628
gsize len;
628-
const gchar *newToken =
629-
g_variant_get_string(restoreTokenVar, &len);
629+
const gchar *newToken = g_variant_get_string(restoreTokenVar, &len);
630630
DEBUG_SCREENCAST("restore_token |%s|\n", newToken);
631631

632632
storeRestoreToken(oldToken, newToken);
@@ -640,6 +640,8 @@ static void callbackScreenCastStart(
640640
if (streams) {
641641
g_variant_unref(streams);
642642
}
643+
644+
gtk_main_quit();
643645
}
644646

645647
ScreenCastResult portalScreenCastStart(const gchar *token) {
@@ -693,9 +695,7 @@ ScreenCastResult portalScreenCastStart(const gchar *token) {
693695
DEBUG_SCREENCAST("Failed to start session: %s\n", err->message);
694696
ERR_HANDLE(err);
695697
} else {
696-
while (!helper.isDone) {
697-
g_main_context_iteration(NULL, TRUE);
698-
}
698+
gtk_main();
699699
}
700700

701701
unregisterScreenCastCallback(&helper);

‎modules/javafx.graphics/src/main/native-glass/gtk/screencast_portal.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@
3030
#ifndef _SCREENCAST_PORTAL_H
3131
#define _SCREENCAST_PORTAL_H
3232

33-
#include "gtk_interface.h"
33+
#include <gdk/gdk.h>
34+
#include <gdk/gdkx.h>
35+
#include <gtk/gtk.h>
36+
#include <gio/gunixfdlist.h>
3437

35-
#define PORTAL_TOKEN_TEMPLATE "awtPipewire%lu"
38+
#define PORTAL_TOKEN_TEMPLATE "fxPipewire%lu"
3639
#define PORTAL_REQUEST_TEMPLATE "/org/freedesktop/portal/desktop/" \
37-
"request/%s/awtPipewire%lu"
40+
"request/%s/fxPipewire%lu"
3841

3942
void debug_screencast(const char *__restrict fmt, ...);
4043

0 commit comments

Comments
 (0)
Please sign in to comment.