I'm writing an ncurses app that displays the files in a directory, and takes the file chosen by the user and opens in in vim, the problem is that when I hit ctrl z to temporarily close vim, after resuming and closing vim, my program is messed up in quite a few ways.
Runable example here https://pastebin.com/tEdLkaPP Running on Linux 6.5.2 with ncurses version 6.4.2
Part of code that forks and opens vim with execl
def_prog_mode(); endwin();
pid_t pid = fork();
if (pid == -1) {
perror("fork");
} else if (pid == 0) {
execl("vim", "vim", <file>, NULL);
} else {
int child_return = 1;
waitpid(-1, &child_return, WUNTRACED);
}
reset_prog_mode();
redrawwin(stdscr);
// Redraws the window
Code that deletes ncurses windows and calls endwin()
exit:
delwin(win);
delwin(bottom_win);
delwin(win_border);
delwin(bottom_border);
endwin();
return 0;
I've tried calling def_prog_mode() when the child process gets stopped with SIGSTOP, and then calling reset_prog_mode() when it gets SIGCONT, but that doesn't change anything.
Code for handing the signals
int child_return = 1;
while(!WIFEXITED(child_return))
{
waitpid(-1, &child_return, WUNTRACED | WCONTINUED);
if(WIFSTOPPED(child_return))
def_prog_mode();
else if (WIFCONTINUED(child_return))
reset_prog_mode();
}
After looking at https://stackoverflow.com/a/4891565/4769313 from Sir Jo Black's answer, I realized that if I handled SIGTSTP in a custom signal handler, I would need to run kill(getpid(), SIGSTOP) to actually get the process to stop. So with the custom handlers below, everything seems to work as intended. One caveat is that you have to register the signal handlers after initscr to or ncurses may overwrite your signal handlers.
void sig_tstp(__attribute__((unused))int signal)
{
endwin();
kill(getpid(), SIGSTOP);
}
void sig_cont(__attribute__((unused))int signal)
{
reset_prog_mode();
}
int main()
{
initscr();
signal(SIGTSTP, sig_tstp);
signal(SIGCONT, sig_cont);
// ...
}
The forking code no longer needed to handle the child's process until the child terminated, so now it looks like this
def_prog_mode(); endwin();
pid_t pid = fork();
if (pid == -1) {
perror("fork");
} else if (pid == 0) {
execl(program, program, buf, NULL);
} else {
int child_return = 1;
waitpid(-1, &child_return, 0);
}
reset_prog_mode();