I'm currently playing around with curses and trying to understand how everything reacts. I was thinking I was making progress until I stumbled on this simple piece of code:
import curses
def main(stdscr: curses.window) -> None:
stdscr.addstr(0, 0, "A")
# stdscr.refresh()
win = curses.newwin(2, 2, 1, 0)
win.addstr(0, 0, "B")
win.refresh()
stdscr.getch()
curses.wrapper(main)
What I don't understand here is why the result is a screen with only an A, and no B. What I also find intriguing is that if I uncomment the commented line, I get both an A and a B.
Could someone please explain what's happening, or at least point me to some document that explains it.
Thanks in advance!
The "B" is actually written to the terminal, but immediately overwritten in the repainting done for the refresh done as a side-effect of stdscr.getch()
. The manual page says that getch
does that:
If the window is not a pad, and it has been moved or modified since the last call to
wrefresh
,wrefresh
will be called before another character is read.
Initializing curses makes stdscr
cleared on the first time it is painted. Again, in the manual page (for initscr
):
initscr
also causes the first call torefresh
(3x) to clear the screen.
I generated this listing using a utility (unmap
) which makes everything readable (actually spaces aren't converted), taking the output to the terminal using script
(and limiting the display to a 5x5 screen):
Script started on 2021-04-09 19:08:24-04:00 [TERM="screen.xterm-new" TTY="/dev/pts/0" COLUMNS="80" LINES="40"]
\n
\E[?1049h
\E[22;0;0t
\E[1;5r
\E(B
\E[m
\E[4l
\E[?7h
\E[?1h
\E=
\E[39;49m
\E[39;49m
\E[37m
\E[40m
\E[1;1H
\E[2;1H
\E[3;1H
\E[4;1H
\E[5;1H
\E[?7l
\E[?7h
\E[H
\E[2dB
\E[39;49m
\E[37m
\E[40m
\E[H
\E[2;1H
\E[3;1H
\E[4;1H
\E[5;1H
\E[?7l
\E[?7h
\E[HA
\E[?1l
\E>
\E[39;49m\r
\E[5d
\E[K
\E[5;1H
\E[?1049l
\E[23;0;0t\r
\E[?1l
\E>
\nScript done on 2021-04-09 19:08:24-04:00 [COMMAND_EXIT_CODE="0"]
\n
The "B" comes out on this line:
\E[2dB
and the "A" on this:
\E[HA
(the other characters are part of escape sequences).
Uncommenting that line finishes the repainting needed by initscr
, and there's no remaining work for stdscr
needed in the stdscr.getch()
call (so none of the new window is overwritten).