From 1887f44f62ab460406381f8d83017cb1b25466ff Mon Sep 17 00:00:00 2001 From: crschnick Date: Thu, 25 Jun 2026 16:11:51 +0000 Subject: [PATCH] Fixes --- .../java/io/xpipe/app/rdp/FreeRdpClient.java | 55 +++++++++++++++++-- .../java/io/xpipe/app/util/FlatpakCache.java | 7 ++- .../xpipe/app/webtop/WebtopAppListDialog.java | 10 +++- .../app/webtop/WebtopAppListManager.java | 9 ++- dist/changelog/24.0.md | 2 + 5 files changed, 74 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/rdp/FreeRdpClient.java b/app/src/main/java/io/xpipe/app/rdp/FreeRdpClient.java index abccaa916..5fcd38f63 100644 --- a/app/src/main/java/io/xpipe/app/rdp/FreeRdpClient.java +++ b/app/src/main/java/io/xpipe/app/rdp/FreeRdpClient.java @@ -1,5 +1,6 @@ package io.xpipe.app.rdp; +import io.xpipe.app.issue.ErrorEventFactory; import io.xpipe.app.process.CommandBuilder; import io.xpipe.app.process.CommandSupport; import io.xpipe.app.process.LocalShell; @@ -17,8 +18,14 @@ import lombok.extern.jackson.Jacksonized; @Builder public class FreeRdpClient implements ExternalRdpClient { - @Override - public void launch(RdpLaunchConfig configuration) throws Exception { + @Value + private static class Executable { + + CommandBuilder commandBase; + boolean v3; + } + + private Executable getX11CommandBase() throws Exception { CommandBuilder exec; var v3 = CommandSupport.isInLocalPath("xfreerdp3"); if (!v3) { @@ -29,8 +36,7 @@ public class FreeRdpClient implements ExternalRdpClient { exec = FlatpakCache.getRunCommand("com.freerdp.FreeRDP"); v3 = true; } else { - CommandSupport.isInPathOrThrow(LocalShell.getShell(), "xfreerdp"); - exec = CommandBuilder.of().add("xfreerdp"); + return null; } } else { CommandSupport.isInPathOrThrow(LocalShell.getShell(), "xfreerdp"); @@ -41,12 +47,49 @@ public class FreeRdpClient implements ExternalRdpClient { } else { exec = CommandBuilder.of().add("xfreerdp3"); } + return new Executable(exec, v3); + } + + private Executable getWaylandCommandBase() throws Exception { + CommandBuilder exec; + var v3 = CommandSupport.isInLocalPath("wlfreerdp3"); + if (!v3) { + var v2 = CommandSupport.isInLocalPath("wlfreerdp"); + if (!v2 && OsType.ofLocal() == OsType.LINUX) { + var flatpak = FlatpakCache.getApp("com.freerdp.FreeRDP"); + if (flatpak.isPresent()) { + exec = FlatpakCache.getRunCommand("com.freerdp.FreeRDP", "sdl-freerdp"); + v3 = true; + } else { + return null; + } + } else { + // No wayland build exists on macOS + return null; + } + } else { + exec = CommandBuilder.of().add("wlfreerdp3"); + } + return new Executable(exec, v3); + } + + @Override + public void launch(RdpLaunchConfig configuration) throws Exception { + var preferWayland = OsType.ofLocal() == OsType.LINUX && "wayland".equalsIgnoreCase(System.getenv("XDG_SESSION_TYPE")); + var exec = preferWayland ? getWaylandCommandBase() : getX11CommandBase(); + if (exec == null && preferWayland) { + exec = getX11CommandBase(); + } + + if (exec == null) { + throw ErrorEventFactory.expected(new IllegalStateException("Unable to find a FreeRDP v2 or v3 installation")); + } var file = writeRdpConfigFile(configuration.getTitle(), configuration.getConfig()); var b = CommandBuilder.of() - .add(exec) + .add(exec.getCommandBase()) .addFile(file.toString()) - .add(v3 ? "/cert:ignore" : "/cert-ignore") + .add(exec.isV3() ? "/cert:ignore" : "/cert-ignore") .add("/dynamic-resolution") .add("/network:auto") .add("/compression") diff --git a/app/src/main/java/io/xpipe/app/util/FlatpakCache.java b/app/src/main/java/io/xpipe/app/util/FlatpakCache.java index be0e7c278..808c6b0a9 100644 --- a/app/src/main/java/io/xpipe/app/util/FlatpakCache.java +++ b/app/src/main/java/io/xpipe/app/util/FlatpakCache.java @@ -54,10 +54,15 @@ public class FlatpakCache { } public static CommandBuilder getRunCommand(String id) { + return getRunCommand(id, null); + } + + public static CommandBuilder getRunCommand(String id, String exec) { return CommandBuilder.of() .add("flatpak", "run") .add("--filesystem=" + AppSystemInfo.ofLinux().getTemp()) .add("--filesystem=host") - .addQuoted(id); + .addQuoted(id) + .addQuoted(exec); } } diff --git a/app/src/main/java/io/xpipe/app/webtop/WebtopAppListDialog.java b/app/src/main/java/io/xpipe/app/webtop/WebtopAppListDialog.java index 005db6641..46ac78dac 100644 --- a/app/src/main/java/io/xpipe/app/webtop/WebtopAppListDialog.java +++ b/app/src/main/java/io/xpipe/app/webtop/WebtopAppListDialog.java @@ -9,13 +9,20 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import java.util.List; +import java.util.concurrent.Semaphore; public class WebtopAppListDialog { + private static Semaphore semaphore = new Semaphore(1); private static List lastShown; - public static synchronized void show(List include) { + public static void show(List include) { + if (!semaphore.tryAcquire()) { + return; + } + if (!include.isEmpty() && include.equals(lastShown)) { + semaphore.release(); return; } @@ -36,5 +43,6 @@ public class WebtopAppListDialog { }, true, true)); modal.show(); lastShown = include; + semaphore.release(); } } diff --git a/app/src/main/java/io/xpipe/app/webtop/WebtopAppListManager.java b/app/src/main/java/io/xpipe/app/webtop/WebtopAppListManager.java index 7c386bc04..721a45c5a 100644 --- a/app/src/main/java/io/xpipe/app/webtop/WebtopAppListManager.java +++ b/app/src/main/java/io/xpipe/app/webtop/WebtopAppListManager.java @@ -5,6 +5,7 @@ import io.xpipe.app.core.AppSystemInfo; import io.xpipe.app.issue.ErrorEventFactory; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.process.ShellScript; +import io.xpipe.app.storage.DataStorage; import io.xpipe.app.terminal.TerminalLaunch; import io.xpipe.app.update.AppDistributionType; import io.xpipe.app.util.GlobalTimer; @@ -36,7 +37,7 @@ public class WebtopAppListManager { var m = new WebtopAppListManager(); m.load(); INSTANCE = m; - INSTANCE.showDialogIfNeeded(null); + INSTANCE.showDialogIfNeeded(); AppPrefs.get().passwordManager().addListener((observable, oldValue, newValue) -> { INSTANCE.showDialogIfNeeded(); @@ -157,6 +158,12 @@ public class WebtopAppListManager { } } + var fromStores = DataStorage.get().getStoreEntries().stream() + .map(entry -> entry.getProvider() != null ? entry.getProvider().getRequiredWebtopApp(entry) : null) + .filter(Objects::nonNull) + .toList(); + all.addAll(fromStores); + return all.stream().filter(webtopApp -> webtopApp != null).collect(Collectors.toCollection(LinkedHashSet::new)); } diff --git a/dist/changelog/24.0.md b/dist/changelog/24.0.md index 73e52b324..9b6d9cc87 100644 --- a/dist/changelog/24.0.md +++ b/dist/changelog/24.0.md @@ -42,6 +42,8 @@ The latest release of the [apple container runtime](https://github.com/apple/con - The custom agent setting now resolves environment variables in the socket path - The terminal prompts like starship will now work when /tmp execution is disabled - The Windows Credentials password manager integration now also supports retrieving Windows credentials in addition to generic ones +- RDP file entries have been replaced by a new RDP file import to create regular RDP connections from a file +- Add support for the wayland versions of freerdp ## Fixes