track child exit code on window object

This commit is contained in:
Kovid Goyal 2026-07-06 08:23:09 +05:30
parent 6614f402ee
commit c1660a4e83
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 15 additions and 6 deletions

View file

@ -1039,11 +1039,13 @@ class Boss:
for w, val in changes.items():
w.ignore_focus_changes = val
def on_child_death(self, window_id: int) -> None:
def on_child_death(self, window_id: int, child_died: bool, exit_status: int) -> None:
prev_active_window = self.active_window
window = self.window_id_map.pop(window_id, None)
if window is None:
return
window.child_died, window.child_exit_status = child_died, exit_status
window.child_exit_code = os.waitstatus_to_exitcode(exit_status)
with self.suppress_focus_change_events():
for close_action in window.actions_on_close:
try:

View file

@ -63,10 +63,11 @@ typedef struct {
typedef struct {
Screen *screen;
bool needs_removal;
bool needs_removal, child_died;
int fd;
unsigned long id;
pid_t pid;
int exit_status;
} Child;
static const Child EMPTY_CHILD = {0};
@ -564,7 +565,8 @@ parse_input(ChildMonitor *self) {
// the python function could call into other functions in this module
remove_count--;
if (remove_notify[remove_count].screen) do_parse(self, remove_notify[remove_count].screen, now, true);
PyObject *t = PyObject_CallFunction(self->death_notify, "k", remove_notify[remove_count].id);
PyObject *t = PyObject_CallFunction(
self->death_notify, "kOi", remove_notify[remove_count].id, remove_notify[remove_count].child_died ? Py_True : Py_False, remove_notify[remove_count].exit_status);
if (t == NULL) PyErr_Print();
else Py_DECREF(t);
FREE_CHILD(remove_notify[remove_count]);
@ -1553,11 +1555,13 @@ handle_signal(const siginfo_t *siginfo, void *data) {
}
static void
mark_child_for_removal(ChildMonitor *self, pid_t pid) {
mark_child_for_removal(ChildMonitor *self, pid_t pid, int exit_status) {
children_mutex(lock);
for (size_t i = 0; i < self->count; i++) {
if (children[i].pid == pid) {
children[i].needs_removal = true;
children[i].exit_status = exit_status;
children[i].child_died = true;
break;
}
}
@ -1589,7 +1593,7 @@ reap_children(ChildMonitor *self, bool enable_close_on_child_death) {
if (pid == -1) {
if (errno != EINTR) break;
} else if (pid > 0) {
if (enable_close_on_child_death) mark_child_for_removal(self, pid);
if (enable_close_on_child_death) mark_child_for_removal(self, pid, status);
mark_monitored_pids(pid, status);
} else break;
}

View file

@ -1444,7 +1444,7 @@ class ChildMonitor:
def __init__(
self,
death_notify: Callable[[int], None],
death_notify: Callable[[int, bool, int], None],
dump_callback: Optional[Callable[[int, str, Any], None]],
talk_fd: int = -1,
listen_fd: int = -1,

View file

@ -692,6 +692,9 @@ class Window:
serialized_id: int = 0
show_title_bar: bool = False # must be set before calling set_geometry
is_drag_target: bool = False # highlight this window's title bar as a drop target
child_died: bool = False
child_exit_status: int = 0
child_exit_code: int = 0
@classmethod
@contextmanager