0

I'm trying to learn ncurses writting code in C++. I use Linux Mint and g++ for compiling. I've written the below code. I have two subwindows created with newwin() that always keep their size. What i want is when i shrink the window and then expand nothing to change. When i shrink horizontally and then expand, the windows edges are drawn as expected, nothing is corrupted. But when i do the same thing vertically it looks like a scrolling is done and blank lines are added below. Why does this happen when the change is vertical but when it's horizontal everything is fine?

#include <ncurses.h>
#include <signal.h>


WINDOW * mainWin;
WINDOW * sideWin;
void resizeHandler(int);

int main()
{
    int mainwinStartX = 0;
    int mainwinStartY = 0;
    int mainwinWidth;
    int mainwinHeight;
    int sidewinStartX;
    int sidewinStartY = 0;
    int sidewinWidth;
    int sidewinHeight;
    signal(SIGWINCH, resizeHandler);

    initscr();
    noecho();
    refresh();

    // Prepairing mainWin sizes
    mainwinWidth = float(2)/3 * COLS;
    mainwinHeight = LINES;
    // Prepairing side win sizes
    sidewinStartX = mainwinWidth;
    sidewinWidth = COLS - mainwinWidth;
    sidewinHeight = LINES;
    // creating window objects
    mainWin = newwin(mainwinHeight, mainwinWidth, mainwinStartY, mainwinStartX);
    sideWin = newwin(sidewinHeight, sidewinWidth, sidewinStartY, sidewinStartX);
    box(mainWin, 0, 0);
    box(sideWin, 0, 0);
    wrefresh(mainWin);
    wrefresh(sideWin);
    while (getch() != 'x'){}
    endwin();
    return 0;
}


void resizeHandler(int sigNumber){}
jww
  • 97,681
  • 90
  • 411
  • 885
saavedra29
  • 26
  • 5

2 Answers2

1

ncurses does/doesn't update layout of windows other than stdscr intentionally. The behavior is described in the manual page for wresize:

This is an extension to the curses library. It reallocates storage for an ncurses window to adjust its dimensions to the specified values. If either dimension is larger than the current values, the window's data is filled with blanks that have the current background rendition (as set by wbkgdset) merged into them.

ncurses does not attempt to guess the application's preferred layout. The resizeterm manual page points out that an application should check for KEY_RESIZE returned from wgetch and update the layout:

The KEY_RESIZE alerts an application that the screen size has changed, and that it should repaint special features such as pads that cannot be done automatically.

The given example program has a couple of problems:

  • it refers to a resize-handler (not shown) which is not needed (since initscr assigns one — see Signal Handlers in the initscr manual page)
  • the fragment shown here:
    box(mainWin, 0, 0);
    box(sideWin, 0, 0);
    wrefresh(mainWin);
    wrefresh(sideWin);
    while (getch() != 'x'){}

will not repaint the boxes in mainWin and sideWin because:

  • with ncurses' signal handler, the loop with getch would repaint stdscr, wiping out the other windows.
  • with some other signal handler, ncurses would not know that the screensize had changed, and you would get unpredictable results.

You may be seeing some partial overwrite of those windows; I only see the entire window being overwritten with the (blank) stdscr.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • Thank's Thomas Dickey for the response! Although i read it 4-5 times i didn't understand many things. Using the KEY_RESIZE definition though, as you suggested, helped a lot. Thank's again. – saavedra29 May 30 '17 at 19:05
0

The code that actually worked for me:

#include <ncurses.h>

#define WIDTH 80
#define HEIGHT 24

WINDOW * mainWin;
WINDOW * sideWin;

int main()
{
    int mainwinStartX = 0;
    int mainwinStartY = 0;
    int mainwinWidth;
    int mainwinHeight;
    int sidewinStartX;
    int sidewinStartY = 0;
    int sidewinWidth;
    int sidewinHeight;

    initscr();
    noecho();
    refresh();
    // Prepairing mainWin sizes
    mainwinWidth = float(2)/3 * WIDTH;
    mainwinHeight = HEIGHT;
    // Prepairing side win sizes
    sidewinStartX = mainwinWidth;
    sidewinWidth = WIDTH - mainwinWidth;
    sidewinHeight = HEIGHT;
    // creating window objects
    mainWin = newwin(mainwinHeight, mainwinWidth, mainwinStartY, mainwinStartX);
    sideWin = newwin(sidewinHeight, sidewinWidth, sidewinStartY, sidewinStartX);
    box(mainWin, 0, 0);
    box(sideWin, 0, 0);
    wrefresh(mainWin);
    wrefresh(sideWin);
    while (TRUE)
    {
        int input = getch();
        if (input == 'x')
            break;
        if (input == KEY_RESIZE)
        {
                refresh();
                delwin(mainWin);
                delwin(sideWin);
                mainWin = newwin(mainwinHeight, mainwinWidth, mainwinStartY, mainwinStartX);
                sideWin = newwin(sidewinHeight, sidewinWidth, sidewinStartY, sidewinStartX);
                box(mainWin, 0, 0);
                box(sideWin, 0, 0);
                wrefresh(mainWin);
                wrefresh(sideWin);

        }
    }
    endwin();
    return 0;
}

I used the KEY_RESIZE as Thomas suggested and had to delete and recreate the windows on every "resize" key event of the terminal window.

saavedra29
  • 26
  • 5
  • Actually there is no need to delete and create new windows in my case. Instead one can just use "wresize" to keep the windows at a stable size. – saavedra29 Jun 01 '17 at 20:11