I'm having a hard time understanding the problem with a window in ncurses. I created a layout of several windows and want to have a function that will border a window. Look like this:
int main() {
use_env(TRUE);
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
WINDOW *win_corner = newwin(WCLINES, WCCOLS, WCX, WCY);
choose_lvl(win_corner);
...
}
int choose_lvl(WINDOW *win) {
box(win, 0, 0);
wrefresh(win);
refresh();
int c, curr_option = 0;
init_pair(1, COLOR_CYAN, COLOR_BLACK);
attron(COLOR_PAIR(1));
mvwprintw(win, 1, 1, "Choose your level");
...
}
It seems like box() doesnt have any effect at all - what could it be? My current theory is to suppose something wrong with the coordinates of the window.
refresh() refreshes the updates on stdscr. newwin() creates an independant window. A refresh on stdscr does not update the alternate window. The same without refresh() in choose_lvl() function would work fine as you would force update only on the alternate window.
You can also create a sub-window of stdscr with subwin() to make refresh() update the whole hierarchy:
#include <unistd.h>
#include <curses.h>
#define WCLINES 10
#define WCCOLS 80
#define WCX 4
#define WCY 4
int choose_lvl(WINDOW *win) {
box(win, 0, 0);
//wrefresh(win);
//refresh();
int c, curr_option = 0;
init_pair(1, COLOR_CYAN, COLOR_BLACK);
attron(COLOR_PAIR(1));
mvwprintw(win, 1, 1, "Choose your level");
refresh();
return 0;
}
int main() {
use_env(TRUE);
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
//WINDOW *win_corner = newwin(WCLINES, WCCOLS, WCX, WCY);
WINDOW *win_corner = subwin(stdscr, WCLINES, WCCOLS, WCX, WCY);
choose_lvl(win_corner);
// quick&dirty pause to suspend program execution
// right after the windows display
pause();
return 0;
}
Execution:
$ gcc win.c -lncurses
$ ./a.out
The result is:
I'm using the following simple ncurses code to create a menu:
#include <menu.h>
#include <stdlib.h>
ITEM **it;
MENU *me;
WINDOW *win;
void quit(void)
{
int i;
unpost_menu(me);
free_menu(me);
for(i=0; i<=4; i++)
{
free_item(it[i]);
}
free(it);
delwin(win);
endwin();
}
int main(void)
{
int ch;
initscr();
atexit(quit);
clear();
noecho();
curs_set(0);
cbreak();
nl();
keypad(stdscr, TRUE);
start_color();
init_pair(1, COLOR_WHITE, COLOR_BLUE);
init_pair(2, COLOR_BLUE, COLOR_YELLOW);
bkgd(COLOR_PAIR(1));
it = (ITEM **)calloc(5, sizeof(ITEM *));
it[0] = new_item("M1", "Menueeintrag 1");
it[1] = new_item("M2", "Menueeintrag 2");
it[2] = new_item("M3", "Menueeintrag 3");
it[3] = new_item("Ende", "Programm beenden");
it[4] = 0;
me = new_menu(it);
win = newwin(8, 30, 5, 5);
set_menu_win (me, win);
set_menu_sub (me, derwin(win, 4, 28, 3, 2));
box(win, 0, 0);
mvwaddstr(win, 1, 2, "***** Testmenü *****");
set_menu_fore(me, COLOR_PAIR(1)|A_REVERSE);
set_menu_back(me, COLOR_PAIR(1));
wbkgd(win, COLOR_PAIR(2));
post_menu(me);
mvaddstr(14, 3, "Programm mittels Menü oder F1-Funktionstaste beenden");
refresh();
wrefresh(win);
while((ch=getch()) != KEY_F(1))
{
switch(ch)
{
case KEY_DOWN:
menu_driver(me, REQ_DOWN_ITEM);
break;
case KEY_UP:
menu_driver(me, REQ_UP_ITEM);
break;
case 0xA: /* Return- bzw. Enter-Taste -> ASCII-Code */
if(item_index(current_item(me)) == 3)
exit(0);
}
wrefresh(win);
}
return (0);
}
But at the positions where I put text there is always a weird misalignment. You can see it when looking at the border of the menu as well as at the right border of the terminal on the same height as the help text.
Screenshot of the resulting program
That umlaut on "Testmenü" tells the story: it is probably encoded as UTF-8, which uses two bytes:
252: 252 0374 0xfc text "\374" utf8 \303\274
If the locale settings are (for example) en_US, then that tells ncurses that the terminal doesn't use UTF-8, and it will assume that the string is actually ISO-8859-1. In that case, it counts both bytes of that character as separate cells on the screen.
Meanwhile, the terminal may be using UTF-8 encoding (and display the character as shown in the screenshot). But if the locale settings do not correspond to the terminal, you'll see odd stuff like that.
My laptop is Macbook Pro.
I installed libxcb on it and tried a simple example that x.org given:
#include <unistd.h> /* pause() */
#include <xcb/xcb.h>
int main ()
{
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_window_t win;
/* Open the connection to the X server */
c = xcb_connect (NULL, NULL);
/* Get the first screen */
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
/* Ask for our window's Id */
win = xcb_generate_id(c);
/* Create the window */
xcb_create_window (c, /* Connection */
XCB_COPY_FROM_PARENT, /* depth (same as root)*/
win, /* window Id */
screen->root, /* parent window */
0, 0, /* x, y */
150, 150, /* width, height */
10, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
screen->root_visual, /* visual */
0, NULL); /* masks, not used yet */
/* Map the window on the screen */
xcb_map_window (c, win);
/* Make sure commands are sent before we pause, so window is shown */
xcb_flush (c);
pause (); /* hold client until Ctrl-C */
return 0;
}
But there is no window shown on screen. Is there something I forget?
I'm making a program with ncurses that splits the screen into two windows. The top screen can accept input, and by pressing '#' it will move all the text down the the bottom window and wipe the top window. In my code I'm trying to use copywin() to replace the bottom window, but it will not paste the wording in the second window. This is what I have...
#include <ncurses.h>
int main(int argc, char *argv[])
{
// Declare variables for windows and sizes
WINDOW *top_win, *bottom_win;
int maxx, maxy, halfy, flag = 0, ch;
// Start curses
initscr();
noecho();
refresh();
// get the max x's and y's
getmaxyx(stdscr, maxy, maxx);
halfy = maxy >> 1;
// Start color
start_color();
init_pair(1, COLOR_BLACK, COLOR_WHITE);
init_pair(2, COLOR_WHITE, COLOR_CYAN);
init_pair(3, COLOR_RED, COLOR_WHITE);
// Make windows
top_win = newwin(halfy, maxx, 0, 0);
wbkgd(top_win, COLOR_PAIR(1));
wrefresh(top_win);
bottom_win = newwin(halfy, maxx, halfy, 0);
wbkgd(bottom_win, COLOR_PAIR(2));
wrefresh(bottom_win);
// Allow functions keys
keypad(top_win, TRUE);
keypad(bottom_win, TRUE);
// while loop to get input
while((ch = getch()) != '`')
{
if(ch == '#')
{
if(flag == 1)
{
flag = 0;
}
else
{
flag = 1;
}
}
else if(ch == '#')
{
//waddstr(bottom_win, "testing");
copywin(top_win, bottom_win, 0, 0, halfy, 0, halfy, maxx, TRUE);
//overwrite(top_win, bottom_win);
//werase(top_win);
}
else if(flag != 1)
{
waddch(top_win, ch | COLOR_PAIR(1));
}
else if(flag == 1)
{
waddch(top_win, ch | COLOR_PAIR(3));
}
wrefresh(top_win);
wrefresh(bottom_win);
}
// end curses
delwin(top_win);
delwin(bottom_win);
endwin();
return 0;
}
I know I can print to the window using the '#' character because of my commented out, testing statement. I've also just tried using overwrite(), but that didn't work either. Am I simply getting the arguments mixed up, or is it something else? Any Ideas? Thank you in advance!
copywin checks the given rows/columns, and decides that your destination rectangle doesn't lie completely within the destination window. Here's a quick fix for your program:
--- foo.c.orig 2017-02-13 16:13:12.000000000 -0500
+++ foo.c 2017-02-13 16:30:18.037987489 -0500
## -51,7 +51,7 ##
else if(ch == '#')
{
//waddstr(bottom_win, "testing");
- copywin(top_win, bottom_win, 0, 0, halfy, 0, halfy, maxx, TRUE);
+ copywin(top_win, bottom_win, 0, 0, 0, 0, halfy - 1, maxx - 1, TRUE);
//overwrite(top_win, bottom_win);
//werase(top_win);
}
## -73,4 +73,3 ##
endwin();
return 0;
}
Rows and columns are numbered from zero through the last row/column (which is one less than the window size), so I subtracted one from the dmaxrow and dmaxcol parameters. The fifth parameter dminrow was past the bottom of the window.
ncurses checks the parameters. Regarding compatibility and portability, running the same program with Solaris curses (changing "ncurses.h" to "curses.h") dumps core.
The manual page could be improved, but it's clear enough regarding colors:
only text where the two windows overlap is copied
I don't have a good explanation for why it works, but as long as xoff and yoff are at least 1 in the code below, the data from the upper window is copied to the lower window OK (and cleared from the upper window). The colour isn't copied. If either offset is 0, the data is not copied. The string testing is added at the top-left of the lower window — it can be omitted and the copied material is still OK.
#include <ncurses.h>
int main(void)
{
// Declare variables for windows and sizes
WINDOW *top_win, *bottom_win;
int maxx, maxy, halfy, flag = 0, ch;
// Start curses
initscr();
noecho();
refresh();
// get the max x's and y's
getmaxyx(stdscr, maxy, maxx);
halfy = maxy >> 1;
// Start color
start_color();
init_pair(1, COLOR_BLACK, COLOR_WHITE);
init_pair(2, COLOR_WHITE, COLOR_CYAN);
init_pair(3, COLOR_RED, COLOR_WHITE);
// Make windows
top_win = newwin(halfy, maxx, 0, 0);
wbkgd(top_win, COLOR_PAIR(1));
wrefresh(top_win);
bottom_win = newwin(halfy, maxx, halfy, 0);
wbkgd(bottom_win, COLOR_PAIR(2));
wrefresh(bottom_win);
// Allow functions keys
// keypad(top_win, TRUE);
// keypad(bottom_win, TRUE);
// while loop to get input
int xoff = 1;
int yoff = 1;
while ((ch = getch()) != '`')
{
if (ch == '#')
{
if (flag == 1)
{
flag = 0;
}
else
{
flag = 1;
}
}
else if (ch == '#')
{
waddstr(bottom_win, "testing");
// copywin(top_win, bottom_win, 0, 0, halfy, 0, halfy, maxx, TRUE);
copywin(top_win, bottom_win, 0, 0, yoff, xoff, halfy-yoff, maxx-xoff, TRUE);
// overwrite(top_win, bottom_win);
werase(top_win);
}
else if (flag != 1)
{
waddch(top_win, ch | COLOR_PAIR(1));
}
else if (flag == 1)
{
waddch(top_win, ch | COLOR_PAIR(3));
}
wrefresh(top_win);
wrefresh(bottom_win);
}
// end curses
delwin(top_win);
delwin(bottom_win);
endwin();
return 0;
}
Testing on Mac running macOS Sierra 10.12.3 with GCC 6.3.0, using the local -lncurses library.
I am embedding my command line application into a ncurses-TUI.
My application (client/server) should be able to print a lot lines if needed, but it must stays into the windows I defined :
/* Removed code */
ITEM **my_items;
int c;
MENU *my_menu;
WINDOW *my_menu_win;
int n_choices, i;
// Initialize curses
initscr(); // initializes the screen
start_color();
cbreak();
noecho();
keypad(stdscr, TRUE);
init_pair(1, COLOR_RED, COLOR_BLACK);
/* Removed code */
/* Create items */
n_choices = ARRAY_SIZE(choices);
my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
for(i = 0; i < n_choices; ++i)
{
my_items[i] = new_item(choices[i], choices[i]);
}
/* Removed code */
/* Create menu */
my_menu = new_menu((ITEM **)my_items);
/* Set menu option not to show the description */
menu_opts_off(my_menu, O_SHOWDESC);
/* Create the window to be associated with the menu */
my_menu_win = newwin(WIN_HEIGHT, WIN_WIDTH, WIN_YPOS, WIN_XPOS);
keypad(my_menu_win, TRUE);
/* Set main window and sub window */
set_menu_win(my_menu, my_menu_win);
set_menu_sub(my_menu, derwin(my_menu_win, WIN_HEIGHT/2, WIN_WIDTH/2, WIN_HEIGHT/2-3, WIN_WIDTH/2-10));
/* Set menu mark to the string " * " */
set_menu_mark(my_menu, ">");
/* Print a border around the main window and print a title */
box(my_menu_win, 0, 0);
/* Removed code */
/* Post the menu */
post_menu(my_menu);
wrefresh(my_menu_win);
endwin(); //resets the screen
}
1 How can I add a windows inside this windows with a scrolling content where all the output that usually goes to the terminal would be print
2 ...or is it possible to link that windows with the terminal output ?