Run this Python code and resize window. It will get a KEY_RESIZE
and exit.
import curses
import signal
stdscr = None
def handler(num, _):
curses.endwin()
stdscr.refresh()
stdscr = curses.initscr()
curses.cbreak()
stdscr.keypad(1)
stdscr.refresh()
signal.signal(signal.SIGWINCH, handler)
while True:
ch = stdscr.getch()
if ch == curses.KEY_RESIZE: break
curses.endwin()
Where is this KEY_RESIZE
injected?
I also tested with C code:
#include <ncurses.h>
#include <signal.h>
WINDOW *stdscr = NULL;
void handler(int num) {
endwin();
wrefresh(stdscr);
}
int main()
{
stdscr = initscr();
cbreak();
keypad(stdscr, 1);
wrefresh(stdscr);
signal(SIGWINCH, handler);
while (1) {
int ch = wgetch(stdscr);
if (ch == KEY_RESIZE) break;
}
endwin();
return 0;
}
Run it and resize it, then press a key, it will get a KEY_RESIZE
exit. Why do we have to press a key to get a KEY_RESIZE
in C code, which is not necessary in Python code?
That's by design... since curses doesn't have anything like an event-loop, it has to tell the application that a SIGWINCH
was detected, and that the curses library has updated its data structures to work with the new terminal size. (Having a signal handler in the application that an application could use to tell the curses library would not work better, and having the curses library do this is simpler, anyway).
The initscr
and getch
manual pages mention this SIGWINCH
feature.
As for "where" it does this: that's in _nc_update_screensize, which checks a flag set by the signal handler, and is called from several places including doupdate
(which refresh
and getch
call). That will inject a KEY_RESIZE
whether or not there was actually a SIGWINCH
, if the screensize has changed.
Now... it's possible to have signal handlers chain, by calling the original handler from newly-established handlers. (Calling signal
in a C program returns the current handler's address). ncurses will only add its handler at initialization time, so one (unlikely) possibility is that the python code is perhaps reusing the underlying handler when it adds its own.
However, there's a larger problem in the examples: they are making curses calls in the signal handlers. That's unsafe in C (the reason why ncurses' signal handlers only set a flag). Perhaps in python those handlers are wrapped -- or just due to timing you're getting unexpected behavior.