shutdown hook
This commit is contained in:
@@ -236,6 +236,18 @@ public final class Compositor {
|
|||||||
tabs.clear();
|
tabs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals and reaps every pane's shell process across all tabs, without tearing down render
|
||||||
|
* state. Intended for a JVM shutdown hook (SIGTERM/SIGINT/SIGHUP), so child shells get the
|
||||||
|
* configured close signal instead of being orphaned when jprototerm itself is killed. Safe to
|
||||||
|
* call off the FX thread and idempotent; see {@link TerminalPane#terminateSession()}.
|
||||||
|
*/
|
||||||
|
public void terminateSessions() {
|
||||||
|
for (Tab tab : List.copyOf(tabs)) {
|
||||||
|
tab.terminateSessions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Tab currentTab() {
|
private Tab currentTab() {
|
||||||
return tabs.get(currentTabIndex);
|
return tabs.get(currentTabIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ public final class Main extends Application {
|
|||||||
compositor.close();
|
compositor.close();
|
||||||
Platform.exit();
|
Platform.exit();
|
||||||
});
|
});
|
||||||
|
// If jprototerm itself is killed (SIGTERM/SIGINT/SIGHUP, e.g. a logout or `kill`), the JVM
|
||||||
|
// runs shutdown hooks before exiting. Send each pane's configured close signal here so the
|
||||||
|
// child shells are terminated rather than orphaned. Only the ptys are touched (not ghostty's
|
||||||
|
// native state), so this is safe to run concurrently with the still-live render loop. A
|
||||||
|
// SIGKILL of jprototerm bypasses hooks entirely; nothing can help there.
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(compositor::terminateSessions, "shell-cleanup"));
|
||||||
|
|
||||||
StackPane root = new StackPane(compositor.canvas(), compositor.imageOverlay());
|
StackPane root = new StackPane(compositor.canvas(), compositor.imageOverlay());
|
||||||
compositor.canvas().widthProperty().bind(root.widthProperty());
|
compositor.canvas().widthProperty().bind(root.widthProperty());
|
||||||
|
|||||||
@@ -423,4 +423,14 @@ final class Tab implements AutoCloseable {
|
|||||||
tiled.clear();
|
tiled.clear();
|
||||||
floating.clear();
|
floating.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals and reaps every pane's shell process without tearing down render state. Safe to call
|
||||||
|
* off the FX thread (see {@link TerminalPane#terminateSession()}); iterates snapshots so a
|
||||||
|
* concurrent close on the FX thread can't trigger a {@link java.util.ConcurrentModificationException}.
|
||||||
|
*/
|
||||||
|
public void terminateSessions() {
|
||||||
|
List.copyOf(tiled).forEach(TerminalPane::terminateSession);
|
||||||
|
List.copyOf(floating).forEach(TerminalPane::terminateSession);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public final class TerminalPane implements AutoCloseable, RenderTarget {
|
|||||||
// tracking meaningful: update() accumulates dirty since the last resetDirty().
|
// tracking meaningful: update() accumulates dirty since the last resetDirty().
|
||||||
private final RenderState renderState = new RenderState();
|
private final RenderState renderState = new RenderState();
|
||||||
private RenderStateSnapshot cachedSnapshot;
|
private RenderStateSnapshot cachedSnapshot;
|
||||||
private ShellSession session;
|
private volatile ShellSession session;
|
||||||
// Run once (on the FX thread) when this pane's process exits on its own, so the owning tab can
|
// Run once (on the FX thread) when this pane's process exits on its own, so the owning tab can
|
||||||
// remove it. Set by the Tab that creates the pane; null until then.
|
// remove it. Set by the Tab that creates the pane; null until then.
|
||||||
private Runnable onExit;
|
private Runnable onExit;
|
||||||
@@ -380,4 +380,17 @@ public final class TerminalPane implements AutoCloseable, RenderTarget {
|
|||||||
renderState.close();
|
renderState.close();
|
||||||
terminal.close();
|
terminal.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals and reaps just the shell process, leaving the render/native state untouched. Unlike
|
||||||
|
* {@link #close()} this is safe to call off the FX thread — notably from a JVM shutdown hook,
|
||||||
|
* which runs concurrently with the live render loop — because it only touches the pty (a child
|
||||||
|
* process and fd), not ghostty's terminal handles. Idempotent; the OS reclaims the rest on exit.
|
||||||
|
*/
|
||||||
|
public void terminateSession() {
|
||||||
|
ShellSession current = session;
|
||||||
|
if (current != null) {
|
||||||
|
current.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user