Merge branch 'jdk24' into 16-release

This commit is contained in:
crschnick
2025-04-07 17:13:58 +00:00
parent 9892fc7564
commit ce9c358dd5
18 changed files with 45 additions and 168 deletions
+3 -3
View File
@@ -32,8 +32,8 @@ If you are on Linux or macOS, you can easily accomplish that by running
```bash
curl -s "https://get.sdkman.io" | bash
. "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 22.0.2-graalce
sdk default java 22.0.2-graalce
sdk install java 24-graalce
sdk default java 24-graalce
```
.
On Windows, you have to manually install a JDK, e.g. from [Adoptium](https://adoptium.net/temurin/releases/?version=21).
@@ -65,7 +65,7 @@ many IDEs still have problems building this project properly.
For example, you can't build this project in eclipse or vscode as it will complain about missing modules.
The tested and recommended IDE is IntelliJ.
When setting up the project in IntelliJ, make sure that the correct JDK (Java 22)
When setting up the project in IntelliJ, make sure that the correct JDK (Java 24)
is selected both for the project and for gradle itself.
## Contributing guide
@@ -60,11 +60,7 @@ public class AppDesktopIntegration {
AppOpenArguments.handle(List.of(e.getURI().toString()));
});
// Do it this way to prevent IDE inspections from complaining
var c = Class.forName(
ModuleLayer.boot().findModule("java.desktop").orElseThrow(), "com.apple.eawt.Application");
var m = c.getDeclaredMethod("addAppEventListener", SystemEventListener.class);
m.invoke(c.getMethod("getApplication").invoke(null), new AppReopenedListener() {
Desktop.getDesktop().addAppEventListener(new AppReopenedListener() {
@Override
public void appReopened(AppReopenedEvent e) {
OperationMode.switchToAsync(OperationMode.GUI);
@@ -9,7 +9,6 @@ import io.xpipe.app.update.WebtopUpdater;
import io.xpipe.app.util.LocalExec;
import io.xpipe.app.util.Translatable;
import io.xpipe.core.process.OsType;
import io.xpipe.core.util.ModuleHelper;
import io.xpipe.core.util.XPipeInstallation;
import javafx.beans.value.ObservableValue;
@@ -54,7 +53,7 @@ public enum AppDistributionType implements Translatable {
return;
}
if (!ModuleHelper.isImage()) {
if (!AppProperties.get().isImage()) {
type = DEVELOPMENT;
return;
}
@@ -6,7 +6,6 @@ import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.resources.AppResources;
import io.xpipe.core.process.OsType;
import io.xpipe.core.util.ModuleHelper;
import io.xpipe.core.util.ModuleLayerLoader;
import io.xpipe.core.util.XPipeInstallation;
@@ -209,10 +208,6 @@ public class AppExtensionManager {
return Optional.empty();
}
ext.get().getModule().getPackages().forEach(pkg -> {
ModuleHelper.exportAndOpen(pkg, ext.get().getModule());
});
TrackEvent.withInfo("Loaded extension module")
.tag("name", ext.get().getName())
.tag("dir", dir.toString())
@@ -4,7 +4,6 @@ import io.xpipe.app.core.check.AppUserDirectoryCheck;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.util.ModuleHelper;
import io.xpipe.core.util.XPipeDaemonMode;
import lombok.Getter;
@@ -84,7 +83,12 @@ public class AppProperties {
}
var referenceDir = Files.exists(appDir) ? appDir : Path.of(System.getProperty("user.dir"));
image = ModuleHelper.isImage();
image = AppProperties.class
.getProtectionDomain()
.getCodeSource()
.getLocation()
.getProtocol()
.equals("jrt");
arguments = AppArguments.init(args);
fullVersion = Optional.ofNullable(System.getProperty("io.xpipe.app.fullVersion"))
.map(Boolean::parseBoolean)
@@ -90,7 +90,6 @@ public class AppTrayIcon {
EventQueue.invokeLater(() -> {
try {
tray.add(this.trayIcon);
fixBackground();
} catch (Exception e) {
// This can sometimes fail on Linux
ErrorEvent.fromThrowable("Unable to add TrayIcon", e).expected().handle();
@@ -98,67 +97,12 @@ public class AppTrayIcon {
});
}
private void fixBackground() {
// Ugly fix to show a transparent background on Linux
if (OsType.getLocal().equals(OsType.LINUX)) {
EventQueue.invokeLater(() -> {
try {
Field peerField;
peerField = TrayIcon.class.getDeclaredField("peer");
peerField.setAccessible(true);
var peer = peerField.get(this.trayIcon);
// If tray initialization fails, this can be null
if (peer == null) {
return;
}
var canvasField = peer.getClass().getDeclaredField("canvas");
canvasField.setAccessible(true);
Component canvas = (Component) canvasField.get(peer);
canvas.setBackground(new Color(0, 0, 0, 0));
var frameField = peer.getClass().getDeclaredField("eframe");
frameField.setAccessible(true);
Frame frame = (Frame) frameField.get(peer);
frame.setTitle("XPipe");
} catch (Exception e) {
ErrorEvent.fromThrowable(e).omit().handle();
}
});
}
}
public void hide() {
EventQueue.invokeLater(() -> {
tray.remove(trayIcon);
});
}
public void showInfoMessage(String title, String message) {
if (OsType.getLocal().equals(OsType.MACOS)) {
showMacAlert(title, message, "Information");
} else {
EventQueue.invokeLater(() -> this.trayIcon.displayMessage(title, message, TrayIcon.MessageType.INFO));
}
}
public void showInfoMessage(String message) {
this.showInfoMessage(null, message);
}
public void showWarningMessage(String title, String message) {
if (OsType.getLocal().equals(OsType.MACOS)) {
showMacAlert(title, message, "Warning");
} else {
EventQueue.invokeLater(() -> this.trayIcon.displayMessage(title, message, TrayIcon.MessageType.WARNING));
}
}
public void showWarningMessage(String message) {
this.showWarningMessage(null, message);
}
public void showErrorMessage(String title, String message) {
if (OsType.getLocal().equals(OsType.MACOS)) {
showMacAlert(title, message, "Error");
@@ -167,22 +111,6 @@ public class AppTrayIcon {
}
}
public void showErrorMessage(String message) {
this.showErrorMessage(null, message);
}
public void showMessage(String title, String message) {
if (OsType.getLocal().equals(OsType.MACOS)) {
showMacAlert(title, message, "Message");
} else {
EventQueue.invokeLater(() -> this.trayIcon.displayMessage(title, message, TrayIcon.MessageType.NONE));
}
}
public void showMessage(String message) {
this.showMessage(null, message);
}
private void showMacAlert(String subTitle, String message, String title) {
String execute = String.format(
"display notification \"%s\"" + " with title \"%s\"" + " subtitle \"%s\"",
@@ -1,13 +1,13 @@
package io.xpipe.app.core.check;
import io.xpipe.app.core.AppLogs;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.util.ModuleHelper;
public class AppDebugModeCheck {
public static void printIfNeeded() {
if (!ModuleHelper.isImage() || !AppLogs.get().getLogLevel().equals("trace")) {
if (!AppProperties.get().isImage() || !AppLogs.get().getLogLevel().equals("trace")) {
return;
}
@@ -3,7 +3,6 @@ package io.xpipe.app.core.window;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.NativeBridge;
import io.xpipe.core.util.ModuleHelper;
import javafx.stage.Window;
@@ -33,7 +32,7 @@ public class NativeMacOsWindowControl {
}
public boolean setAppearance(boolean seamlessFrame, boolean darkMode) {
if (!ModuleHelper.isImage() || !AppProperties.get().isFullVersion()) {
if (!AppProperties.get().isImage() || !AppProperties.get().isFullVersion()) {
return false;
}
@@ -16,7 +16,6 @@ import io.xpipe.app.terminal.TerminalPromptManager;
import io.xpipe.app.util.PlatformState;
import io.xpipe.app.util.PlatformThread;
import io.xpipe.core.process.ShellScript;
import io.xpipe.core.util.ModuleHelper;
import javafx.beans.property.*;
import javafx.beans.value.ObservableBooleanValue;
@@ -345,7 +344,7 @@ public class AppPrefs {
}
public boolean isDevelopmentEnvironment() {
return developerMode().getValue() && !ModuleHelper.isImage();
return developerMode().getValue() && !AppProperties.get().isImage();
}
public ObservableValue<PasswordManager> passwordManager() {
@@ -3,7 +3,6 @@ package io.xpipe.app.util;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.core.process.OsType;
import io.xpipe.core.util.ModuleHelper;
import io.xpipe.core.util.XPipeInstallation;
import com.sun.jna.Library;
@@ -26,7 +25,7 @@ public class NativeBridge {
}
public static Optional<MacOsLibrary> getMacOsLibrary() {
if (!ModuleHelper.isImage() || !AppProperties.get().isFullVersion()) {
if (!AppProperties.get().isImage() || !AppProperties.get().isFullVersion()) {
return Optional.empty();
}
+9 -3
View File
@@ -127,9 +127,12 @@ project.ext {
devJavafxVersion = '25-ea+10'
platformName = getPlatformName()
jvmRunArgs = [
"--add-opens", "java.base/java.lang=io.xpipe.app",
"--add-opens", "java.base/java.lang=io.xpipe.core",
"--add-opens", "java.desktop/java.awt=io.xpipe.app",
"--enable-native-access=com.sun.jna",
"--enable-native-access=javafx.graphics",
"--enable-native-access=javafx.web",
"--sun-misc-unsafe-memory-access=allow",
"--add-opens", "java.base/java.io=io.xpipe.ext.proc",
"--add-opens", "org.apache.commons.io/org.apache.commons.io.input=io.xpipe.ext.proc",
"--add-opens", "net.synedra.validatorfx/net.synedra.validatorfx=io.xpipe.app",
"--add-opens", "java.base/java.nio.file=io.xpipe.app",
"--add-exports", "javafx.graphics/com.sun.javafx.tk=io.xpipe.app",
@@ -145,6 +148,9 @@ project.ext {
"-Djdk.virtualThreadScheduler.parallelism=8"
]
// Use project liliput
jvmRunArgs += ['-XX:+UnlockExperimentalVMOptions', '-XX:+UseCompactObjectHeaders']
// GC config
jvmRunArgs += ['-XX:+UseG1GC', '-Xms300m', '-Xmx4G', '-XX:GCTimeRatio=9', '-XX:+UseStringDeduplication'];
@@ -1,57 +0,0 @@
package io.xpipe.core.util;
import lombok.SneakyThrows;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ModuleHelper {
public static boolean isImage() {
return ModuleHelper.class
.getProtectionDomain()
.getCodeSource()
.getLocation()
.getProtocol()
.equals("jrt");
}
@SneakyThrows
public static Module getEveryoneModule() {
Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
getDeclaredFields0.setAccessible(true);
Field[] fields = (Field[]) getDeclaredFields0.invoke(Module.class, false);
Field modifiers = null;
for (Field each : fields) {
if ("EVERYONE_MODULE".equals(each.getName())) {
modifiers = each;
break;
}
}
modifiers.setAccessible(true);
return (Module) modifiers.get(null);
}
@SneakyThrows
public static void exportAndOpen(String pkg, Module mod) {
if (mod.isExported(pkg) && mod.isOpen(pkg)) {
return;
}
Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredMethods0", boolean.class);
getDeclaredFields0.setAccessible(true);
Method[] fields = (Method[]) getDeclaredFields0.invoke(Module.class, false);
Method modifiers = null;
for (Method each : fields) {
if ("implAddExportsOrOpens".equals(each.getName())) {
modifiers = each;
break;
}
}
modifiers.setAccessible(true);
var e = getEveryoneModule();
modifiers.invoke(mod, pkg, e, false, true);
modifiers.invoke(mod, pkg, e, true, true);
}
}
@@ -55,6 +55,15 @@ public class XPipeInstallation {
return "\"" + command + "\"" + modeOption + suffix;
}
private static boolean isImage() {
return XPipeInstallation.class
.getProtectionDomain()
.getCodeSource()
.getLocation()
.getProtocol()
.equals("jrt");
}
@SneakyThrows
public static Path getCurrentInstallationBasePath() {
var command = ProcessHandle.current().info().command();
@@ -78,7 +87,7 @@ public class XPipeInstallation {
if (name.endsWith("java") || name.endsWith("java.exe")) {
// If we are not an image, we are probably running in a development environment where we want to use the
// working directory
var isImage = ModuleHelper.isImage();
var isImage = isImage();
if (!isImage) {
return Path.of(System.getProperty("user.dir"));
}
@@ -164,7 +173,7 @@ public class XPipeInstallation {
}
public static String getLocalDefaultCliExecutable() {
Path path = ModuleHelper.isImage()
Path path = isImage()
? getCurrentInstallationBasePath()
: Path.of(getLocalDefaultInstallationBasePath());
return path.resolve(getRelativeCliExecutablePath(OsType.getLocal())).toString();
@@ -174,7 +183,7 @@ public class XPipeInstallation {
Path path = getCurrentInstallationBasePath();
// Check for development environment
if (!ModuleHelper.isImage()) {
if (!isImage()) {
if (OsType.getLocal().equals(OsType.WINDOWS)) {
return path.resolve("dist").resolve("logo").resolve("logo.ico");
} else if (OsType.getLocal().equals(OsType.LINUX)) {
@@ -218,7 +227,7 @@ public class XPipeInstallation {
}
public static Path getLangPath() {
if (!ModuleHelper.isImage()) {
if (!isImage()) {
return getCurrentInstallationBasePath().resolve("lang");
}
@@ -234,7 +243,7 @@ public class XPipeInstallation {
}
public static Path getBundledFontsPath() {
if (!ModuleHelper.isImage()) {
if (!isImage()) {
return Path.of("dist", "fonts");
}
+2 -1
View File
@@ -13,7 +13,8 @@ def releaseArguments = distJvmArgs + [
"-Dio.xpipe.app.staging=$rootProject.isStage",
'-Dio.xpipe.app.sentryUrl=https://fd5f67ff10764b7e8a704bec9558c8fe@o1084459.ingest.sentry.io/6094279',
'-Djna.nosys=false',
'-Djna.nounpack=true'
'-Djna.nounpack=true',
'-Xlog:cds'
]
if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) {
+1 -1
View File
@@ -1,4 +1,4 @@
name=GraalVM Community
version=22.0.2
version=24
license=GPL2 with the Classpath Exception
link=https://www.graalvm.org/
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-8.14-20250406024815+0000-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+2 -3
View File
@@ -86,8 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -206,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.