mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-26 10:25:44 +00:00
Merge branch 'jdk24' into 16-release
This commit is contained in:
+3
-3
@@ -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
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
-1
@@ -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
@@ -1,4 +1,4 @@
|
||||
name=GraalVM Community
|
||||
version=22.0.2
|
||||
version=24
|
||||
license=GPL2 with the Classpath Exception
|
||||
link=https://www.graalvm.org/
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user