Ncurses status bar in C

I know I posted on this subject before. But, I have some code that doesn't do what it's supposed to do.

Here's the code:

void draw_statusbar(void) 
{
   int i;
   char sbar[79]; // 79
   wattrset(statusbar, crt2curses(0x19));
   wcolor_set(statusbar, crt2curses(0x19), NULL);
   sprintf(sbar, " %s %s", appname, version);
   for (i = strlen(sbar); i < 80; i++) sbar[i] = 32;
   mvwaddstr(statusbar, 0,0, sbar);
   touchwin(statusbar);
   wrefresh(statusbar);
   touchwin(win);
   textattr(0x07);
}

Here's an illustration of how it's supposed to work.

+--------------------------------------------------------------------+
|                                                                    |
|                                                                    |
|                                                                    |
|                                                                    |
|                                                                    |
+--------------------------------------------------------------------+
| Status bar --- stays on the screen              |
+--------------------------------------------------------------------+

The upper part of the screen (in this crude representation) runs normally, while the status bar stays on the screen until the program is exited. In the current iteration the status bar displays, but once the screen scrolls down, it disappears.

So, my question is, how would I make the status bar stay on the screen until the connection is lost?

EDIT: For clarification, this is actually for a BBS (telnet) client. So, that's what I mean by "connection is lost."

Thank you.

I'm no ncurses expert, but I believe that whatever is scrolling the terminal screen has no knowledge that you are also using ncurses to modify it, and vice versa. If you use ncurses for part of a terminal window, you need to go all-in on ncurses.

Ncurses should be capable of dividing up the display area into panels which move independently. I don't know how hard it would be to make whatever is writing the top area to use a specific subregion of the area (apparently called a curses window to distinguish it from a terminal window).

As I mentioned elsewhere, having a separate status window would be a simpler option. If you want to do this in a single window, you will need to accept the scrolling inputs (control chars and sidebar drags) in curses, and apply them only to the non-status area.

It is insufficient to just redraw the status area periodically -- it will overwrite the last three lines of the terminal display.

As windows can be resized by the user, your constants (79, 80) should be variables derived from ncurses queries in response to a notification of size change. I note the trailing | in your illustration is misaligned.

The integer 32 can be replaced by the perfectly valid integer expression ' '.

to do this effectively/properly create two independent windows (and maybe's panels dependant upon what you are doing )

WINDOW *topWin = newwin(....); /* define shape */
WINDOW *statusWin = newwin(....); /* ditto */

read the documentation on how to do this.
ncurses documentation

OK. I have some code.

void draw_statusbar(void)
{
int parent_x, parent_y;
int bot_bar_size = 3;
initscr();
noecho();
curs_set(FALSE);
getmaxyx(stdscr, parent_y, parent_x);
//WINDOW *top_win = newwin(parent_y - bot_bar_size, parent_x, 0, 0);
WINDOW *bot_bar = newwin(bot_bar_size, parent_x, parent_y - bot_bar_size, 0);
//mvwprintw(top_win, 0, 0, "top_win");
mvwprintw(bot_bar, 0, 0, "bot_bar");
//wrefresh(top_win);
wrefresh(bot_bar);
sleep(5);
//delwin(top_win);
delwin(bot_bar);
endwin();
return 0;
}

The code works, but only until the sleep counter reaches 0.
Anyone know what i'm doing wrong?

Thank you.

The sleep 5 suspends your whole process. So whatever is writing to the area designated by "top_win" (which does not exist because all references to it are entirely commented out) is suspended too.

When the sleep ends, the code that messes up the top part gets to mess it up all over again. You have not fixed the problem in any meaningful way, you have just deferred it.

I repeat: you have to find some way of restricting the "other" code to using top_win, and not the whole terminal window. And I suspect there is no way to make that change without rewriting a substantial amount of code, because any scrolling or data entry in that code is busily working with its own SCREEN* and WINDOW* (if it even uses ncurses at all), not your top_win.

@munkeHoller suggests you read relevant parts of the excellent ncurses documentation, which might show you how to launch your "other" code in its own WINDOW *. The issue is in whatever code you aren't showing us, not in the draw_statusbar() function.

You might also consider how often you will need to call draw_statusbar(): presumably every time the status changes. You won't want to call initscr() every time -- that will clear the top part too. And endwin() will reinitialise the whole terminal screen, not just your status area.

1 Like