I have a program utilizing ncurses
to draw a window with a clock timer. It is constantly being refreshed in an infinite loop. It works as intended, however when I resize the terminal window, the entire image gets messed up and all out of sorts.
I've read some items on SIGWINCH
for ncurses as well as a few others but they are all relying on a wgetch(win)
or getch()
. These calls block the loop waiting for user input. This seems like a pretty standard use-case, so trying to understand what is the procedure for detecting the window resizing without blocking the loop.
Note I am on Windows 11 and to compile I run gcc -o test.exe test.c -lncurses -DNCURSES_STATIC
#include <windows.h>
#include <ncurses/ncurses.h>
#include <time.h>
// default window sizes
#define WINDOW_HEIGHT 16
#define WINDOW_WIDTH 45
#define WINDOW_START_Y 5
#define WINDOW_START_X 5
// prototypes
WINDOW *init_window(void);
int main(void)
{
// global screen init
initscr();
WINDOW *win;
win = init_window();
refresh();
// hide cursor
curs_set(0);
// draw basic box in the window
box(win, 0, 0);
// initialize the timer
time_t now;
while (1) {
// update current UTC time
now = time(0);
struct tm *tmp = gmtime(&now);
// modify terminal window
mvwprintw(win, 1, 1, " _________ ");
mvwprintw(win, 2, 1, " / ======= \\ ");
mvwprintw(win, 3, 1, " / __________\\ ");
mvwprintw(win, 4, 1, " | ___________ | ");
mvwprintw(win, 5, 1, " | | - | | ");
mvwprintw(win, 6, 1, " | | | | ");
mvwprintw(win, 7, 1, " | |_________| |________________ ");
mvwprintw(win, 8, 1, " \\=____________/ REM ) ");
mvwprintw(win, 9, 1, " / \"\"\"\"\"\"\"\"\"\"\" \\ / ");
mvwprintw(win, 10, 1, " / ::::::::::::: \\ =D-' ");
mvwprintw(win, 11, 1, " (_________________) ");
mvwprintw(win, 12, 1, " current time: %02d:%02d:%02d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
wrefresh(win);
}
// clean up
endwin();
return 0;
}
WINDOW* init_window(void)
{
// create new window
WINDOW *win = newwin(WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_START_Y, WINDOW_START_X);
if (!win) {
printf("ERROR: could not create window\n");
exit(1);
}
return win;
}
This should be a duplicate, but the essential point combining SIGWINCH
and polled input doesn't appear.
So... modify the program to
wgetch
with no time delay, to allow it to read KEY_RESIZE
time
is wasteful (check and skip)Here's a modified program which illustrates those points:
#include <stdlib.h>
#include <ncurses.h>
#include <time.h>
// default window sizes
#define WINDOW_HEIGHT LINES - 2
#define WINDOW_WIDTH COLS - 2
#define WINDOW_START_Y 1
#define WINDOW_START_X 1
// prototypes
WINDOW *init_window(void);
int main(void)
{
initscr();
cbreak();
WINDOW *win = init_window();
nodelay(win, TRUE);
// hide cursor
curs_set(0);
// draw basic box in the window
box(win, 0, 0);
// initialize the timer
time_t start = time(0);
while (1) {
if (wgetch(win) == KEY_RESIZE) { // process SIGWINCH
wresize(win, WINDOW_HEIGHT, WINDOW_WIDTH);
clear();
wclear(win);
box(win, 0, 0);
wnoutrefresh(win);
start--; // force a redraw
}
// update current UTC time
time_t now = time(0);
if (now == start)
continue;
start = now;
struct tm *tmp = gmtime(&now);
// modify terminal window
mvwprintw(win, 1, 1, " _________ ");
mvwprintw(win, 2, 1, " / ======= \\ ");
mvwprintw(win, 3, 1, " / __________\\ ");
mvwprintw(win, 4, 1, " | ___________ | ");
mvwprintw(win, 5, 1, " | | - | | ");
mvwprintw(win, 6, 1, " | | | | ");
mvwprintw(win, 7, 1, " | |_________| |________________ ");
mvwprintw(win, 8, 1, " \\=____________/ REM ) ");
mvwprintw(win, 9, 1, " / \"\"\"\"\"\"\"\"\"\"\" \\ / ");
mvwprintw(win, 10, 1, " / ::::::::::::: \\ =D-' ");
mvwprintw(win, 11, 1, " (_________________) ");
mvwprintw(win, 12, 1, " current time: %02d:%02d:%02d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
wnoutrefresh(win);
doupdate();
}
// clean up
endwin();
return 0;
}
WINDOW* init_window(void)
{
// create new window
WINDOW *win = newwin(WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_START_Y, WINDOW_START_X);
if (!win) {
printf("ERROR: could not create window\n");
exit(1);
}
return win;
}
Now... the answer as posted is ambiguous regarding whether this is (for example) using Cygwin, MinGW or MSYS2. The MinGW configuration doesn't provide a workable KEY_RESIZE
; if you are using that, this question should be marked as a duplicate. Otherwise, if the underlying libraries are more-or-less POSIX, the program will work for you.