ncurses Routines in Rapid Succession
Chapter 13: chgat
, mvchgat
, wchgat
, mvwchgat
chgat
style functions modify the attributes of a sequence of characters already printed on the screen, without reprinting them.
- Fast and visually smooth for highlighting and toggling styles without redrawing full lines.
Common Signature:
chgat(int n, attr_t attr, short color_pair, const void *opts);
n
: Number of characters to affect. Use-1
to go to end of line.attr
: Attribute flags likeA_BOLD
,A_REVERSE
, etc.color_pair
: The index of the color pair (from init_pair).opts
: AlwaysNULL
. Reserved for future cursed extensions.
The Family Tree:
Function | Context | Cursor Affects? | Uses a WINDOW ? | Coordinates? |
---|---|---|---|---|
chgat() | stdscr | Yes | No | Current pos |
mvchgat() | stdscr | Yes | No | Moves cursor |
wchgat() | custom window | Yes | Yes | Current pos |
mvwchgat() | custom window | Yes | Yes | Moves cursor |
💡 Practical Differences 🧼 chgat()
- Applies to the default window (stdscr)
- Starts at the current cursor position
- Doesn’t move the cursor, just modifies stuff starting from it
🚶 mvchgat(y, x, ...)
- Moves the cursor to (y, x) on stdscr
- Then applies the attribute change from there
- Returns the cursor to the position after the change
🪟 wchgat(win, ...)
- Applies to a specific WINDOW
- Uses the window's cursor position
- Use this when you’ve made custom windows (menus, popups, etc.)
🧭 mvwchgat(win, y, x, ...)
- Moves cursor to (y, x) within a specific window
- Applies changes from there
Highlighting a section of text:
mvprintw(0, 0, "This is a test line.");
mvchgat(0, 10, 4, A_REVERSE, 1, NULL); // highlights "test"
Using it in a custom window:
WINDOW *win = newwin(10, 30, 5, 5);
mvwprintw(win, 1, 2, "Item 1 Item 2 Item 3");
mvwchgat(win, 1, 2, 6, A_STANDOUT, 2, NULL); // highlights "Item 1"
Gotchas:
- These functions don’t change what’s written, only how it looks.
- If you overwrite the text afterward, the attributes are lost unless reapplied.
- You must call
refresh()
(orwrefresh()
) afterward to actually see the effect.
Chapter 14: clrtoeol
/ clrtobot
+ erase()
/ refresh()
The two terminal janitors:
clrtoeol()
cleans from the cursor to the end of the current line.clrtobot()
wipes everything from the cursor down to the bottom of the window, including the current line.
erase()
and clear()
may seem similar on the surface, but underneath, they are a little bit different.
erase()
: Clears the window's contents in memory, but does not force an immediate redraw of the screen.
- Works silently with your next
refresh()
orwrefresh()
. - Ideal for partial updates, flickerless redraws.
erase(); // marks the stdscr for clearing
refresh(); // now it actually shows the cleared screen
clear()
: Same as erase()
, but also tells curses to clear the physical screen completely on the next refresh()
.
- The terminal acts as if it was just launched.
- Can cause flickering
- Good for a fresh, guaranteed blank state.
clear(); // like erase() + "I said CLEAR DAMN IT"
refresh();
#include <ncurses.h>
int main(int argc, char **argv) {
initscr();
noecho();
refresh();
printw("Hello");
mvprintw(1, 0, "PwatPwat");
move(0, 1);
getch();
// clear routines
// to the end of line
clrtoeol();
getch();
mvprintw(2, 0, "To clean");
mvprintw(3, 0, "To clean");
mvprintw(5, 0, "To clean");
mvprintw(10, 0, "To clean");
move(2, 5);
getch();
// to the bottom
clrtobot();
getch();
// erase(); soft clear
// clear(); definitely clear
getch();
endwin();
return 0;
}
Chapter 15: leaveok
/ immedok
/ scrollok
leaveok(win, TRUE)
- Don't care where the cursor is, just leave it wherever.
- Prevents
ncurses
from moving the hardware cursor. - Skips cursor repositioning.
- It's fast.
immedok(win, TRUE)
- Every time I change the window, update it immediately.
- Forces
wrefresh(win)
automatically after everywaddch()
,mvwprintw()
, etc. - Slower, but more dynamic and automatic.
scrollok(win, TRUE)
- If we hit the bottom, just scroll the window down.
- Enables automatic scrolling when adding text past the bottom line.
- Useful for chat logs, terminal output windows, logs, etc.
- Requires enough space (and usually
idlok()
too for smooth scrolling).
#include <ncurses.h>
int main(int argc, char **argv) {
initscr();
noecho();
refresh();
WINDOW *win = newwin(5, 8, 10, 10);
box(win, 0, 0);
/*
// don't really need to know where the cursor is
leaveok(win, true);
wmove(win, 1, 2);
wgetch(win);
*/
/*
// refresh immediately
immedok(win, true);
waddch(win, 'a');
*/
/*
// allow continuous scrolling
scrollok(win, true);
int counter = 0;
while (true) {
chtype ch = (counter % 10) + '0';
waddch(win, ch);
wrefresh(win);
counter++;
}
*/
// clearok(WINDOW *, bool)
getch();
endwin();
return 0;
}
Chapter 16: Background Routines (bkgdset
/ bkgd
/ wbkgdset
/ wbkgd
)
Those are routines to manipulate the background of a named window.
// Background routines
#include <ncurses.h>
int main() {
initscr();
refresh();
clear();
if (!has_colors()) {
return 1;
}
start_color();
init_pair(1, COLOR_BLACK, COLOR_RED);
init_pair(2, COLOR_WHITE, COLOR_BLUE);
// setting attributes for the future
bkgdset(COLOR_PAIR(1));
addch('a');
refresh();
/*
bkgd('a'); fill the background
addch('u');
*/
/*
// bkgd vs wbkgd
bkgd(COLOR_PAIR(1));
refresh();
*/
WINDOW *win = newwin(10, 25, 10, 10);
wbkgdset(win, COLOR_PAIR(2));
wclear(win);
wrefresh(win);
/*
wbkgd(win, COLOR_PAIR(2));
box(win, 0, 0);
wrefresh(win);
*/
getch();
endwin();
return 0;
}
Chapter 17 Free Window memory with delwin()
:
newwin()
allocates memory for a WINDOW structure.delwin()
deallocates that memory, it's likefree()
for windows.
🧼 When to use delwin():
✅ Use it:
- When a window is no longer needed (e.g., after closing a dialog box).
- After calling wclear() and wrefresh() to visually wipe it off the screen.
- In well-structured code where windows are dynamically created and destroyed.
🚫 You can skip it:
- In small toy programs or examples where the window is static and only created once.
- If the program ends right after and the OS will clean up anyway (but that's lazy energy).
// Deleting Window Memory
// Increase security with delwin()
#include <curses.h>
#include <ncurses.h>
int main() {
initscr();
WINDOW *test_win = newwin(10, 25, 0, 0);
box(test_win, 0, 0);
refresh();
wrefresh(test_win);
getch();
wclear(test_win);
wrefresh(test_win);
// ensure all associated memory for WINDOW is deleted
// but, does not erase the visual portion on its own.
// Use wclear(win) and wrefresh(win) first to do so.
delwin(test_win);
refresh();
// wrefresh(test_win); // referencing it after it's been deleted can cause a
// segfault
getch();
endwin();
return 0;
}