More rework

This commit is contained in:
crschnick 2024-10-02 21:12:32 +00:00
parent 4c16545424
commit 86a9383cd2
6 changed files with 131 additions and 23 deletions

View file

@ -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 -> {

View file

@ -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();

View file

@ -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<NativeWinWindowControl> byPid(long pid) {
var ref = new AtomicReference<NativeWinWindowControl>();
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() {

View file

@ -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<InPlaceSecretValue> lockPassword = new SimpleObjectProperty<>();

View file

@ -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();
}

View file

@ -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;