Search code examples
cncurses

Termcaps lines and columns are not changing when I resize the window


I'm trying to get the terminal window size, even when I resize the window, I'm using termcaps for this, the problem is when I resize the window, the values of lines and columns stays the same instead of updating, I also tried using ncurses's LINES and COLS globals, but the same thing happens. Here is a minimal reproductible example:

#include <ncurses.h>
#include <term.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    char * term_type = getenv("TERM");
    int ret;
    int li_cap;
    int co_cap;

    if (!term_type)
    {
        write(2, "TERM env must be set\n", 21);
        return (-1);
    }
    if ((ret = tgetent(NULL, term_type)) == -1)
    {
        write(2, "Could not access to the termcap database\n", 41);
        return (-1);
    }
    if (!ret)
    {
        write(2, "This terminal is not supported by termcaps\n", 43);
        return (-1);
    }
    while (1)
    {
        sleep(1);
        li_cap = tgetnum("li");
        co_cap = tgetnum("co");
        printf("%d %d\n", li_cap, co_cap);
    }
    return (0);
}

So when I resize the window inside the loop, the values stay the same, I want to get the lines and colums in real time, how could I do this with termcaps?


Solution

  • The termcap data and the environment variables COLUMNS and LINES are unreliable and aren't updated upon terminal resizing, especially during program execution. There is another solution for POSIX systems where you can:

    • retrieve the size of the terminal window with ioctl(0, TIOCGWINSZ, &ws)
    • register a signal handler to get notified of terminal size changes.

    Here is a demonstration program:

    #include <stdio.h>
    #include <signal.h>
    #include <termios.h>
    #include <sys/ioctl.h>
    #include <unistd.h>
    
    static volatile unsigned char term_size_updated;
    
    static void term_resize() {
        term_size_updated = 1;
    }
    
    static void term_get_size(int *cols, int *rows) {
        struct winsize ws;
    
        /* get screen dimensions from (pseudo) tty ioctl */
        if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
            *cols = ws.ws_col;
            *rows = ws.ws_row;
        } else {
            *cols = *rows = -1;
        }
    }
    
    int main() {
        struct sigaction sig;
        int cols, rows;
    
        /* set up terminal resize callback */
        sig.sa_handler = term_resize;
        sigemptyset(&sig.sa_mask);
        sig.sa_flags = 0;
        sigaction(SIGWINCH, &sig, NULL);
    
        term_size_updated = 1;
        for (;;) {
            if (term_size_updated) {
                term_size_updated = 0;
                term_get_size(&cols, &rows);
                fprintf(stderr, "term_resize: cols=%d, rows=%d\n", cols, rows);
            }
            sleep(1);
        }
        return 0;
    }