From 86a9383cd29f5a01031ff1e3219715ec57f65bab Mon Sep 17 00:00:00 2001 From: crschnick Date: Wed, 2 Oct 2024 21:12:32 +0000 Subject: [PATCH] More rework --- .../app/comp/base/TerminalViewDockComp.java | 9 +- .../io/xpipe/app/core/AppLayoutModel.java | 13 ++- .../core/window/NativeWinWindowControl.java | 16 ++- .../java/io/xpipe/app/prefs/AppPrefs.java | 7 ++ .../io/xpipe/app/prefs/TerminalCategory.java | 12 ++- .../java/io/xpipe/app/util/TerminalView.java | 97 +++++++++++++++++-- 6 files changed, 131 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/comp/base/TerminalViewDockComp.java b/app/src/main/java/io/xpipe/app/comp/base/TerminalViewDockComp.java index e4a107859..b7bf56713 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/TerminalViewDockComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/TerminalViewDockComp.java @@ -23,9 +23,6 @@ public class TerminalViewDockComp extends SimpleComp { stack.boundsInParentProperty().addListener((observable, oldValue, newValue) -> { update(stack); }); - stack.sceneProperty().addListener((observable, oldValue, newValue) -> { - update(stack); - }); var s = AppMainWindow.getInstance().getStage(); s.xProperty().addListener((observable, oldValue, newValue) -> { update(stack); @@ -41,16 +38,14 @@ public class TerminalViewDockComp extends SimpleComp { }); s.iconifiedProperty().addListener((observable, oldValue, newValue) -> { if (newValue) { - TerminalView.get().onMinimize(); + TerminalView.get().onWindowMinimize(); } else { - TerminalView.get().onFocusGain(); + TerminalView.get().onWindowActivate(); } }); s.focusedProperty().addListener((observable, oldValue, newValue) -> { if (newValue) { TerminalView.get().onFocusGain(); - } else { - TerminalView.get().onFocusLost(); } }); s.addEventFilter(WindowEvent.WINDOW_SHOWN,event -> { diff --git a/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java b/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java index e7cdae97c..51e482594 100644 --- a/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java +++ b/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java @@ -11,6 +11,7 @@ import io.xpipe.app.prefs.AppPrefsComp; import io.xpipe.app.util.Hyperlinks; import io.xpipe.app.util.LicenseProvider; +import io.xpipe.app.util.TerminalView; import javafx.beans.property.Property; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; @@ -64,15 +65,19 @@ public class AppLayoutModel { } public void selectTerminal() { + if (!TerminalView.isSupported()) { + return; + } + selected.setValue(entries.get(2)); } public void selectSettings() { - selected.setValue(entries.get(3)); + selected.setValue(entries.get(TerminalView.isSupported() ? 3 : 2)); } public void selectLicense() { - selected.setValue(entries.get(4)); + selected.setValue(entries.get(TerminalView.isSupported() ? 4 : 3)); } public void selectConnections() { @@ -138,6 +143,10 @@ public class AppLayoutModel { // null) )); + if (!TerminalView.isSupported()) { + l.remove(2); + } + var now = Instant.now(); var zone = ZoneId.of(ZoneId.SHORT_IDS.get("PST")); var phStart = ZonedDateTime.of(2024, 10, 22, 0, 1, 0, 0, zone).toInstant(); diff --git a/app/src/main/java/io/xpipe/app/core/window/NativeWinWindowControl.java b/app/src/main/java/io/xpipe/app/core/window/NativeWinWindowControl.java index cd93f5fa7..ebda828fc 100644 --- a/app/src/main/java/io/xpipe/app/core/window/NativeWinWindowControl.java +++ b/app/src/main/java/io/xpipe/app/core/window/NativeWinWindowControl.java @@ -1,6 +1,7 @@ package io.xpipe.app.core.window; import com.sun.jna.ptr.IntByReference; +import io.sentry.protocol.User; import io.xpipe.app.util.Rect; import javafx.stage.Window; @@ -24,6 +25,11 @@ public class NativeWinWindowControl { public static Optional byPid(long pid) { var ref = new AtomicReference(); User32.INSTANCE.EnumWindows((hWnd, data) -> { + var visible = User32.INSTANCE.IsWindowVisible(hWnd); + if (!visible) { + return true; + } + var wpid = new IntByReference(); User32.INSTANCE.GetWindowThreadProcessId(hWnd, wpid); if (wpid.getValue() == pid) { @@ -59,16 +65,24 @@ public class NativeWinWindowControl { this.windowHandle = windowHandle; } + public boolean isIconified() { + return (User32.INSTANCE.GetWindowLong(windowHandle,User32.GWL_STYLE) & User32.WS_MINIMIZE) != 0; + } + public void alwaysInFront() { orderRelative(new WinDef.HWND(new Pointer( 0xFFFFFFFFFFFFFFFFL))); } + public void defaultOrder() { + orderRelative(new WinDef.HWND(new Pointer( 1))); + } + public void orderRelative(WinDef.HWND predecessor) { User32.INSTANCE.SetWindowPos(windowHandle, predecessor, 0, 0, 0, 0, User32.SWP_NOACTIVATE | User32.SWP_NOMOVE | User32.SWP_NOSIZE); } public void show() { - User32.INSTANCE.ShowWindow(windowHandle,User32.SW_RESTORE); + User32.INSTANCE.ShowWindow(windowHandle, User32.SW_RESTORE); } public void close() { diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java index 0149c637f..e3fc86aea 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java @@ -127,10 +127,17 @@ public class AppPrefs { final BooleanProperty requireDoubleClickForConnections = map(new SimpleBooleanProperty(false), "requireDoubleClickForConnections", Boolean.class); + final BooleanProperty enableTerminalDocking = + map(new SimpleBooleanProperty(true), "enableTerminalDocking", Boolean.class); + public ObservableBooleanValue requireDoubleClickForConnections() { return requireDoubleClickForConnections; } + public ObservableBooleanValue enableTerminalDocking() { + return enableTerminalDocking; + } + @Getter private final Property lockPassword = new SimpleObjectProperty<>(); diff --git a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java index cba814cee..84f4e46e1 100644 --- a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java @@ -10,12 +10,10 @@ import io.xpipe.app.fxcomps.impl.HorizontalComp; import io.xpipe.app.fxcomps.impl.StackComp; import io.xpipe.app.fxcomps.impl.TextFieldComp; import io.xpipe.app.terminal.ExternalTerminalType; -import io.xpipe.app.util.Hyperlinks; -import io.xpipe.app.util.OptionsBuilder; -import io.xpipe.app.util.TerminalLauncher; -import io.xpipe.app.util.ThreadHelper; +import io.xpipe.app.util.*; import javafx.beans.binding.Bindings; +import javafx.beans.property.SimpleBooleanProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.ListCell; @@ -58,7 +56,11 @@ public class TerminalCategory extends AppPrefsCategory { .hide(prefs.terminalType.isNotEqualTo(ExternalTerminalType.CUSTOM))) .addComp(terminalTest) .nameAndDescription("clearTerminalOnInit") - .addToggle(prefs.clearTerminalOnInit)) + .addToggle(prefs.clearTerminalOnInit) + .nameAndDescription("enableTerminalDocking") + .addToggle(prefs.enableTerminalDocking) + .hide(new SimpleBooleanProperty(!TerminalView.isSupported())) + ) .buildComp(); } diff --git a/app/src/main/java/io/xpipe/app/util/TerminalView.java b/app/src/main/java/io/xpipe/app/util/TerminalView.java index d54aff3de..1c1754c45 100644 --- a/app/src/main/java/io/xpipe/app/util/TerminalView.java +++ b/app/src/main/java/io/xpipe/app/util/TerminalView.java @@ -3,6 +3,8 @@ package io.xpipe.app.util; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.core.window.NativeWinWindowControl; import io.xpipe.app.issue.TrackEvent; +import io.xpipe.app.prefs.AppPrefs; +import io.xpipe.core.process.OsType; import javafx.application.Platform; import lombok.AccessLevel; import lombok.Getter; @@ -14,6 +16,10 @@ import java.util.List; public class TerminalView { + public static boolean isSupported() { + return OsType.getLocal() == OsType.WINDOWS; + } + @Value public static class Session { ProcessHandle shell; @@ -42,9 +48,15 @@ public class TerminalView { public abstract void close(); + public abstract boolean isActive(); + public abstract Rect queryBounds(); public final void updateBoundsState() { + if (!isActive()) { + return; + } + var bounds = queryBounds(); if (lastBounds != null && !lastBounds.equals(bounds)) { customBounds = true; @@ -81,7 +93,8 @@ public class TerminalView { @Override public void back() { - NativeWinWindowControl.MAIN_WINDOW.orderRelative(control.getWindowHandle()); + control.defaultOrder(); + // NativeWinWindowControl.MAIN_WINDOW.orderRelative(control.getWindowHandle()); } @Override @@ -96,6 +109,11 @@ public class TerminalView { this.control.close(); } + @Override + public boolean isActive() { + return !control.isIconified(); + } + @Override public Rect queryBounds() { return control.getBounds(); @@ -108,6 +126,10 @@ public class TerminalView { private Rect viewBounds; private boolean viewActive; + public boolean isEnabled() { + return isSupported() && AppPrefs.get().enableTerminalDocking().get(); + } + public synchronized void open(long pid) { var processHandle = ProcessHandle.of(pid); if (processHandle.isEmpty() || !processHandle.get().isAlive()) { @@ -137,6 +159,16 @@ public class TerminalView { return; } terminalInstances.add(new WindowsTerminalInstance(terminal.get(), control.get())); + + TrackEvent.withTrace("Terminal instance opened") + .tag("terminalPid", terminal.get().pid()) + .tag("viewEnabled", isEnabled()) + .handle(); + + if (!isEnabled()) { + return; + } + Platform.runLater(() -> { AppLayoutModel.get().selectTerminal(); }); @@ -154,6 +186,9 @@ public class TerminalView { } public synchronized void toggleView(boolean active) { + TrackEvent.withTrace("Terminal view toggled") + .tag("active", active) + .handle(); if (viewActive == active) { return; } @@ -162,30 +197,59 @@ public class TerminalView { if (active) { terminalInstances.forEach(terminalInstance -> terminalInstance.front()); updatePositions(); + } else { + terminalInstances.forEach(terminalInstance -> terminalInstance.back()); } } - public synchronized void onFocusLost() { - terminalInstances.forEach(terminalInstance -> terminalInstance.back()); - } - public synchronized void onFocusGain() { - terminalInstances.forEach(terminalInstance -> terminalInstance.show()); + TrackEvent.withTrace("Terminal view focus gained") + .handle(); + terminalInstances.forEach(terminalInstance -> { + if (!terminalInstance.isActive()) { + return; + } + + terminalInstance.updateBoundsState(); + if (terminalInstance.isCustomBounds()) { + return; + } + + terminalInstance.show(); + }); } - public synchronized void onMinimize() { + public synchronized void onWindowActivate() { + TrackEvent.withTrace("Terminal view focus gained") + .handle(); terminalInstances.forEach(terminalInstance -> { terminalInstance.updateBoundsState(); if (terminalInstance.isCustomBounds()) { return; } + terminalInstance.show(); + }); + } + + public synchronized void onWindowMinimize() { + TrackEvent.withTrace("Terminal view minimized") + .handle(); + + terminalInstances.forEach(terminalInstance -> { + terminalInstance.updateBoundsState(); + if (terminalInstance.isCustomBounds()) { + return; + } terminalInstance.minimize(); }); } public synchronized void onClose() { + TrackEvent.withTrace("Terminal view closed") + .handle(); + terminalInstances.forEach(terminalInstance -> { terminalInstance.updateBoundsState(); if (terminalInstance.isCustomBounds()) { @@ -197,6 +261,10 @@ public class TerminalView { } private void updatePositions() { + if (viewBounds == null) { + return; + } + terminalInstances.forEach(terminalInstance -> { terminalInstance.updateBoundsState(); if (terminalInstance.isCustomBounds()) { @@ -208,14 +276,27 @@ public class TerminalView { } public void resizeView(int x, int y, int w, int h) { + if (w < 100 || h < 100) { + return; + } + this.viewBounds = new Rect(x,y,w,h); + TrackEvent.withTrace("Terminal view resized") + .tag("rect", viewBounds) + .handle(); if (viewActive) { updatePositions(); } } public void clickView() { - terminalInstances.forEach(terminalInstance -> terminalInstance.updatePosition(viewBounds)); + TrackEvent.withTrace("Terminal view clicked") + .handle(); + + terminalInstances.forEach(terminalInstance -> { + terminalInstance.show(); + terminalInstance.updatePosition(viewBounds); + }); } private static TerminalView INSTANCE;