diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserTerminalDockTabModel.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserTerminalDockTabModel.java index 870acb03e..1d2667893 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserTerminalDockTabModel.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserTerminalDockTabModel.java @@ -66,24 +66,18 @@ public final class BrowserTerminalDockTabModel extends BrowserSessionTab { } opened.set(true); - var sessions = TerminalView.get().getSessions(); - var tv = sessions.stream() - .filter(s -> terminalRequests.contains(s.getRequest()) - && s.getTerminal().isRunning()) - .map(s -> s.getTerminal().controllable()) - .flatMap(Optional::stream) - .toList(); - for (int i = 0; i < tv.size() - 1; i++) { - dockModel.closeTerminal(tv.get(i)); - } + var closed = dockModel.closeOtherTerminals(session.getRequest()); // Closing and opening windows at the same time might be problematic for some bad implementations - if (tv.size() > 1) { + if (closed) { ThreadHelper.sleep(250); } - var toTrack = tv.getLast(); - dockModel.trackTerminal(toTrack, true); + var controllable = session.getTerminal().controllable(); + if (controllable.isEmpty()) { + return; + } + dockModel.trackTerminal(controllable.get(), true); } @Override diff --git a/app/src/main/java/io/xpipe/app/core/mode/AppBaseMode.java b/app/src/main/java/io/xpipe/app/core/mode/AppBaseMode.java index ab77d6de6..4f2d9d82f 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/AppBaseMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/AppBaseMode.java @@ -26,7 +26,7 @@ import io.xpipe.app.process.LocalShell; import io.xpipe.app.pwman.KeePassXcPasswordManager; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorageSyncHandler; -import io.xpipe.app.terminal.TerminalDockManager; +import io.xpipe.app.terminal.TerminalDockHubManager; import io.xpipe.app.terminal.TerminalLauncherManager; import io.xpipe.app.terminal.TerminalView; import io.xpipe.app.update.UpdateAvailableDialog; @@ -149,7 +149,7 @@ public class AppBaseMode extends AppOperationMode { BlobManager.init(); TerminalView.init(); TerminalLauncherManager.init(); - TerminalDockManager.init(); + TerminalDockHubManager.init(); TrackEvent.info("File/Terminal initialization thread completed"); }, () -> { diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreLayoutComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreLayoutComp.java index bad55e010..b4559e614 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreLayoutComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreLayoutComp.java @@ -7,9 +7,8 @@ import io.xpipe.app.comp.base.LeftSplitPaneComp; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.core.window.AppMainWindow; import io.xpipe.app.platform.InputHelper; -import io.xpipe.app.terminal.TerminalDockBrowserComp; import io.xpipe.app.terminal.TerminalDockHubComp; -import io.xpipe.app.terminal.TerminalDockManager; +import io.xpipe.app.terminal.TerminalDockHubManager; import io.xpipe.app.util.ObservableSubscriber; import javafx.scene.input.KeyCode; @@ -52,7 +51,7 @@ public class StoreLayoutComp extends SimpleComp { }); }); - var model = TerminalDockManager.get(); + var model = TerminalDockHubManager.get(); var dock = new TerminalDockHubComp(model.getDockModel()); var stack = new StackPane(comp.createRegion(), dock.createRegion()); stack.getStyleClass().add("store-layout"); diff --git a/app/src/main/java/io/xpipe/app/terminal/PowerShellTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/PowerShellTerminalType.java index 2f53b4d3e..62c852c20 100644 --- a/app/src/main/java/io/xpipe/app/terminal/PowerShellTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/PowerShellTerminalType.java @@ -10,6 +10,11 @@ import java.util.Base64; public class PowerShellTerminalType implements ExternalApplicationType.PathApplication, TrackableTerminalType { + @Override + public TerminalDockMode getDockMode() { + return TerminalDockMode.WITH_BORDER; + } + @Override public TerminalOpenFormat getOpenFormat() { return TerminalOpenFormat.NEW_WINDOW; diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalDockManager.java b/app/src/main/java/io/xpipe/app/terminal/TerminalDockHubManager.java similarity index 82% rename from app/src/main/java/io/xpipe/app/terminal/TerminalDockManager.java rename to app/src/main/java/io/xpipe/app/terminal/TerminalDockHubManager.java index 6512b1de5..c759e41b1 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalDockManager.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalDockHubManager.java @@ -3,7 +3,6 @@ package io.xpipe.app.terminal; import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.platform.LabelGraphic; -import io.xpipe.app.platform.NativeWinWindowControl; import io.xpipe.app.platform.PlatformThread; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.GlobalTimer; @@ -18,10 +17,10 @@ import java.util.Set; import java.util.UUID; @Getter -public class TerminalDockManager { +public class TerminalDockHubManager { public static boolean isSupported() { - if (OsType.ofLocal() == OsType.WINDOWS) { + if (OsType.ofLocal() != OsType.WINDOWS) { return false; } @@ -30,18 +29,23 @@ public class TerminalDockManager { return false; } - var tabs = term.getOpenFormat() != TerminalOpenFormat.NEW_WINDOW; - if (tabs) { - return true; + var tabsSupported = term.getOpenFormat() != TerminalOpenFormat.NEW_WINDOW || TerminalMultiplexerManager.getEffectiveMultiplexer().isPresent(); + if (!tabsSupported) { + return false; } - return TerminalMultiplexerManager.getEffectiveMultiplexer().isPresent(); + var modeSupported = term instanceof TrackableTerminalType t && t.getDockMode() != TerminalDockMode.UNSUPPORTED; + if (!modeSupported) { + return false; + } + + return true; } - private static TerminalDockManager INSTANCE; + private static TerminalDockHubManager INSTANCE; public static void init() { - INSTANCE = new TerminalDockManager(); + INSTANCE = new TerminalDockHubManager(); AppLayoutModel.get().getSelected().addListener((observable, oldValue, newValue) -> { if (AppLayoutModel.get().getEntries().indexOf(newValue) == 0) { @@ -59,7 +63,7 @@ public class TerminalDockManager { }); } - public static TerminalDockManager get() { + public static TerminalDockHubManager get() { return INSTANCE; } @@ -105,11 +109,18 @@ public class TerminalDockManager { } var term = AppPrefs.get().terminalType().getValue(); - controllable.get().removeShadow(); - if (term instanceof TrackableTerminalType t && t.getDockMode() == TerminalDockMode.BORDERLESS) { - controllable.get().removeBorders(); + if (term instanceof TrackableTerminalType t) { + if (t.getDockMode() == TerminalDockMode.UNSUPPORTED) { + return; + } + + controllable.get().removeShadow(); + if (t.getDockMode() == TerminalDockMode.BORDERLESS) { + controllable.get().removeBorders(); + } } dockModel.trackTerminal(controllable.get(), !detached.get()); + dockModel.closeOtherTerminals(session.getRequest()); openDock(); } @@ -157,6 +168,10 @@ public class TerminalDockManager { } public void openTerminal(UUID request) { + if (!isSupported()) { + return; + } + hubRequests.add(request); } diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalDockView.java b/app/src/main/java/io/xpipe/app/terminal/TerminalDockView.java index 552182383..9e8345830 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalDockView.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalDockView.java @@ -6,7 +6,9 @@ import io.xpipe.app.util.Rect; import lombok.Getter; import java.util.HashSet; +import java.util.Optional; import java.util.Set; +import java.util.UUID; public class TerminalDockView { @@ -39,6 +41,19 @@ public class TerminalDockView { } } + public synchronized boolean closeOtherTerminals(UUID request) { + var sessions = TerminalView.get().getSessions(); + var tv = sessions.stream() + .filter(s -> request.equals(s.getRequest()) && s.getTerminal().isRunning()) + .map(s -> s.getTerminal().controllable()) + .flatMap(Optional::stream) + .toList(); + for (int i = 0; i < tv.size() - 1; i++) { + closeTerminal(tv.get(i)); + } + return tv.size() > 1; + } + public synchronized void closeTerminal(ControllableTerminalSession terminal) { if (!terminalInstances.contains(terminal)) { return; 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 89be6e0c2..a5a4adbf2 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalLauncher.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalLauncher.java @@ -214,7 +214,7 @@ public class TerminalLauncher { } for (TerminalPaneConfiguration pane : config.getPanes()) { - TerminalDockManager.get().openTerminal(pane.getRequest()); + TerminalDockHubManager.get().openTerminal(pane.getRequest()); } try {