From cda4d23ddcf53f6819912f4c73b0736894ce3c1e Mon Sep 17 00:00:00 2001 From: crschnick Date: Mon, 27 Apr 2026 00:14:49 +0000 Subject: [PATCH] Rework terminal init --- .../xpipe/app/terminal/TerminalLaunchRequest.java | 8 ++++++++ .../io/xpipe/app/terminal/TerminalLauncher.java | 15 ++++++--------- .../app/terminal/TerminalLauncherManager.java | 12 +++++------- .../app/terminal/TerminalPaneConfiguration.java | 4 ++-- .../java/io/xpipe/app/terminal/TerminalView.java | 5 +++++ .../xpipe/app/util/ControllableWindowProcess.java | 2 ++ .../app/util/ControllableWindowsProcess.java | 5 +++++ .../io/xpipe/app/util/NativeWinWindowControl.java | 7 ++++++- 8 files changed, 39 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalLaunchRequest.java b/app/src/main/java/io/xpipe/app/terminal/TerminalLaunchRequest.java index 3e4763561..dd8960962 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalLaunchRequest.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalLaunchRequest.java @@ -41,6 +41,14 @@ public class TerminalLaunchRequest { @NonFinal CountDownLatch latch; + public TerminalLaunchRequest(UUID request, ProcessControl processControl, TerminalInitScriptConfig config, FilePath workingDirectory) { + this.request = request; + this.processControl = processControl; + this.config = config; + this.workingDirectory = workingDirectory; + this.shellPid = -1; + } + public Path waitForCompletion() throws BeaconServerException { while (true) { if (latch.getCount() > 0) { diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalLauncher.java b/app/src/main/java/io/xpipe/app/terminal/TerminalLauncher.java index f16b30da8..e49ca7bf8 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalLauncher.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalLauncher.java @@ -111,7 +111,7 @@ public class TerminalLauncher { true); var singlePane = new TerminalPaneConfiguration(UUID.randomUUID(), title, 0, script, sc.getShellDialect()); var config = new TerminalLaunchConfiguration(null, title, title, true, List.of(singlePane)); - launch(type, config, new CountDownLatch(0)); + launch(type, config); } } @@ -127,7 +127,6 @@ public class TerminalLauncher { } public static void open(List configs, boolean preferTabs, ExternalTerminalType type) throws Exception { - var latch = new CountDownLatch(configs.size()); var paneList = new ArrayList(); for (Config config : configs) { var entry = config.getEntry(); @@ -149,7 +148,7 @@ public class TerminalLauncher { ? type.additionalInitCommands() : TerminalInitFunction.none()); TerminalLauncherManager.submitAsync( - config.getRequest(), config.getProcessControl(), terminalConfig, config.getDirectory(), latch); + config.getRequest(), config.getProcessControl(), terminalConfig, config.getDirectory()); var paneIndex = configs.indexOf(config); var paneConfig = TerminalPaneConfiguration.create( @@ -199,27 +198,26 @@ public class TerminalLauncher { TerminalMultiplexerManager.registerSessionLaunch(launchConfig); if (launchMultiplexerTabInExistingTerminal(launchConfig)) { - latch.await(); return; } var multiplexerConfig = launchMultiplexerTabInNewTerminal(launchConfig); if (multiplexerConfig.isPresent()) { - launch(type, multiplexerConfig.get(), latch); + launch(type, multiplexerConfig.get()); return; } } var proxyConfig = launchProxy(launchConfig); if (proxyConfig.isPresent()) { - launch(type, proxyConfig.get(), latch); + launch(type, proxyConfig.get()); return; } - launch(type, launchConfig, latch); + launch(type, launchConfig); } - private static void launch(ExternalTerminalType type, TerminalLaunchConfiguration config, CountDownLatch latch) + private static void launch(ExternalTerminalType type, TerminalLaunchConfiguration config) throws Exception { if (type == null) { return; @@ -227,7 +225,6 @@ public class TerminalLauncher { try { type.launch(config); - latch.await(); } catch (Exception ex) { var modMsg = ex.getMessage() != null && ex.getMessage().contains("Unable to find application named") ? ex.getMessage() + " in installed /Applications on this system" diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalLauncherManager.java b/app/src/main/java/io/xpipe/app/terminal/TerminalLauncherManager.java index 91a951517..a48265746 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalLauncherManager.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalLauncherManager.java @@ -36,23 +36,21 @@ public class TerminalLauncherManager { }); } - public static CountDownLatch submitAsync( + public static void submitAsync( UUID request, ProcessControl processControl, TerminalInitScriptConfig config, - FilePath directory, - CountDownLatch latch) { + FilePath directory) { synchronized (entries) { var req = entries.get(request); if (req == null) { - req = new TerminalLaunchRequest(request, processControl, config, directory, -1, null, false, latch); + req = new TerminalLaunchRequest(request, processControl, config, directory); entries.put(request, req); } else { req.setResult(null); } req.setupRequestAsync(); - return req.getLatch(); } } @@ -105,7 +103,7 @@ public class TerminalLauncherManager { } if (req.isSetupCompleted()) { - submitAsync(req.getRequest(), req.getProcessControl(), req.getConfig(), req.getWorkingDirectory(), null); + submitAsync(req.getRequest(), req.getProcessControl(), req.getConfig(), req.getWorkingDirectory()); } try { req.waitForCompletion(); @@ -175,7 +173,7 @@ public class TerminalLauncherManager { } var config = new TerminalInitScriptConfig(ref.get().getName(), false, TerminalInitFunction.none()); - submitAsync(request, control, config, null, null); + submitAsync(request, control, config, null); waitExchange(request); var script = launchExchange(request); try (var sc = LocalShell.getShell().start()) { diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalPaneConfiguration.java b/app/src/main/java/io/xpipe/app/terminal/TerminalPaneConfiguration.java index e4cce0d1d..0855a5f98 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalPaneConfiguration.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalPaneConfiguration.java @@ -86,9 +86,9 @@ public class TerminalPaneConfiguration { var content = """ %s echo 'Transcript started, output file is "sessions\\%s"' - Start-Transcript -Force -LiteralPath "%s" > $Out-Null + Start-Transcript -Force -LiteralPath "%s" | Out-Null & "%s" - Stop-Transcript > $Out-Null + Stop-Transcript | Out-Null echo 'Transcript stopped, output file is "sessions\\%s"' """.formatted( TerminalLauncher.getTerminalRegisterCommand( diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalView.java b/app/src/main/java/io/xpipe/app/terminal/TerminalView.java index 2c0abfad7..eb88b78b2 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalView.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalView.java @@ -276,6 +276,11 @@ public class TerminalView { this.controllable = controllable; } + @Override + public boolean isRunning() { + return super.isRunning() && !controllable.isDestroyed(); + } + public boolean manageBorders() { return terminalType != null && terminalType instanceof TrackableTerminalType t diff --git a/app/src/main/java/io/xpipe/app/util/ControllableWindowProcess.java b/app/src/main/java/io/xpipe/app/util/ControllableWindowProcess.java index cc0881e2f..9dc595b48 100644 --- a/app/src/main/java/io/xpipe/app/util/ControllableWindowProcess.java +++ b/app/src/main/java/io/xpipe/app/util/ControllableWindowProcess.java @@ -45,6 +45,8 @@ public abstract class ControllableWindowProcess { public abstract boolean isActive(); + public abstract boolean isDestroyed(); + public abstract Rect queryBounds(); public void updateBoundsState() { diff --git a/app/src/main/java/io/xpipe/app/util/ControllableWindowsProcess.java b/app/src/main/java/io/xpipe/app/util/ControllableWindowsProcess.java index 50d6b5241..b5ee1f44e 100644 --- a/app/src/main/java/io/xpipe/app/util/ControllableWindowsProcess.java +++ b/app/src/main/java/io/xpipe/app/util/ControllableWindowsProcess.java @@ -136,6 +136,11 @@ public final class ControllableWindowsProcess extends ControllableWindowProcess return true; } + @Override + public boolean isDestroyed() { + return control.isDestroyed(); + } + @Override public Rect queryBounds() { return control.getBounds(); diff --git a/app/src/main/java/io/xpipe/app/util/NativeWinWindowControl.java b/app/src/main/java/io/xpipe/app/util/NativeWinWindowControl.java index 8791b9e75..1bf67d833 100644 --- a/app/src/main/java/io/xpipe/app/util/NativeWinWindowControl.java +++ b/app/src/main/java/io/xpipe/app/util/NativeWinWindowControl.java @@ -67,7 +67,8 @@ public class NativeWinWindowControl { var wpid = new IntByReference(); User32.INSTANCE.GetWindowThreadProcessId(hWnd, wpid); if (wpid.getValue() == pid) { - refs.add(new NativeWinWindowControl(hWnd)); + var c = new NativeWinWindowControl(hWnd); + refs.add(c); } return true; }, @@ -153,6 +154,10 @@ public class NativeWinWindowControl { return User32.INSTANCE.IsWindowVisible(windowHandle); } + public boolean isDestroyed() { + return !User32.INSTANCE.IsWindow(windowHandle); + } + public void moveToFront() { orderRelative(new WinDef.HWND(new Pointer(0))); }