cncursescursestui

windows not showing when the terminal is made smaller (ncurses, c)


I'm trying to make a program that has 2 windows side by side that scale to fit the terminal. However the windows only show when the terminal is made larger, not smaller.

I was wondering if it was a terminal problem but I tried it on another terminal, Kitty, and it was the same as my current terminal, st.

A clip of my problem is linked, and code is below. https://imgur.com/a/cAjpZit

Any help is appreciated, thanks from Jamie.

#include <ncurses.h>

WINDOW *CreateNewWin(int mainWinHeight, int mainWinWidth, int startY, int startX) {
    WINDOW *localWin;

    localWin = newwin(mainWinHeight, mainWinWidth, startY, startX);
    box(localWin, 0, 0); 
    wrefresh(localWin); 
    return localWin;
}

void DestroyWin(WINDOW *localWin) {
    wborder(localWin, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
    wrefresh(localWin);
    delwin(localWin);
}

int main(int argc, char *argv[]) {
    WINDOW *mainWin;
    WINDOW *detailsWin;

    int mainWinHeight, mainWinWidth;
    int detailsWinHeight, detailsWinWidth;
    int padding = 1;

    initscr();            
    cbreak();             
    keypad(stdscr, TRUE); 

    int yMax, xMax;
    getmaxyx(stdscr, yMax, xMax);

    mainWinHeight = yMax - (2 * padding);
    mainWinWidth = xMax / 2 - (2 * padding);

    detailsWinHeight = yMax - (2 * padding);
    detailsWinWidth = xMax / 2 - (2 * padding);

    char title[] = "Test app";
    attron(A_BOLD);
    mvprintw(0, 0, title);
    attroff(A_BOLD);

    mvprintw(yMax - 1, 1, "Press F1 to quit");
    refresh();

    mainWin = CreateNewWin(mainWinHeight, mainWinWidth, padding, padding);
    detailsWin = CreateNewWin(detailsWinHeight, detailsWinWidth, padding, xMax / 2 + padding);

    int ch;

    while ((ch = getch()) != KEY_F(1)) {
        switch (ch) {
            case KEY_RESIZE:
                getmaxyx(stdscr, yMax, xMax);

                mainWinHeight = yMax - 2 * padding;
                mainWinWidth = xMax / 2 - 2 * padding;
                detailsWinHeight = yMax - (2 * padding);
                detailsWinWidth = xMax / 2 - (2 * padding);

                DestroyWin(mainWin);
                mainWin = CreateNewWin(mainWinHeight, mainWinWidth, padding, padding);

                DestroyWin(detailsWin);
                detailsWin = CreateNewWin(detailsWinHeight, detailsWinWidth, padding, xMax / 2 + padding);

                break;
            default:
                break;
        }
    }

    endwin(); // End curses mode
    return 0;
}

Solution

  • When the terminal is shrunk, you have to call endwin() and to reinit curses. I also noted that you call getmaxyx, but COLS and LINES are automatically refreshed:

    void init() {
        initscr();            
        cbreak();             
        keypad(stdscr, TRUE); 
    }
    
    int main(int argc, char *argv[]) {
        WINDOW *mainWin;
        WINDOW *detailsWin;
    
        int mainWinHeight, mainWinWidth;
        int detailsWinHeight, detailsWinWidth;
        int padding = 1;
    
        init();
    
        mainWinHeight = LINES - (2 * padding);
        mainWinWidth = COLS / 2 - (2 * padding);
    
        detailsWinHeight = LINES - (2 * padding);
        detailsWinWidth = COLS / 2 - (2 * padding);
    
        char title[] = "Test app";
        attron(A_BOLD);
        mvprintw(0, 0, title);
        attroff(A_BOLD);
    
        mvprintw(LINES - 1, 1, "Press F1 to quit");
        refresh(); 
    
        mainWin = CreateNewWin(mainWinHeight, mainWinWidth, padding, padding);
        detailsWin = CreateNewWin(detailsWinHeight, detailsWinWidth, padding, COLS / 2 + padding);
    
        int ch;
    
        while ((ch = getch()) != KEY_F(1)) {
            switch (ch) {
                case KEY_RESIZE:
                    mainWinHeight = LINES - 2 * padding;
                    mainWinWidth = COLS / 2 - 2 * padding;
                    detailsWinHeight = LINES - (2 * padding);
                    detailsWinWidth = COLS / 2 - (2 * padding);
                    
                    // reset ncurses
                    endwin();
                    init();
                    refresh();
    
                    DestroyWin(mainWin);
                    mainWin = CreateNewWin(mainWinHeight, mainWinWidth, padding, padding);
                    
                    DestroyWin(detailsWin);
                    detailsWin = CreateNewWin(detailsWinHeight, detailsWinWidth, padding, COLS / 2 + padding);
                    
                    break;
                default:
                    break;
            }
        }
    
        endwin(); // End curses mode
        return 0;
    }