JamieBuckerton
JamieBuckerton

Reputation: 23

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;
}

Upvotes: 2

Views: 83

Answers (2)

Thomas Dickey
Thomas Dickey

Reputation: 54455

When you (re)create the windows, you should provide a way for curses to keep track of which window is to be refreshed last. The getch call does a wrefresh(stdscr) (the same effect as refresh(), while the CreateNewWin function does a newwin and wrefresh on the re-created window. If you had used wnoutrefresh and then doupdate, then curses can sort those screen updates out, and repaint only the chunks which change a given cell.

Not calling delwin for the re-created windows aggravates the situation, because ncurses has already resized those before returning KEY_RESIZE -- and there are pending changes to repaint -- when getch is called. If your program discarded the old window with delwin, its associated updates would be discarded.

Actually, using wresize (and mvwin) to update a window rather than recreating it is more direct.

(calling endwin/refresh doesn't change any of that).

Upvotes: 1

Mathieu
Mathieu

Reputation: 9619

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;
}

Upvotes: 1

Related Questions