Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 like A_BOLD, A_REVERSE, etc.
  • color_pair: The index of the color pair (from init_pair).
  • opts: Always NULL. Reserved for future cursed extensions.

The Family Tree:

FunctionContextCursor Affects?Uses a WINDOW?Coordinates?
chgat()stdscrYesNoCurrent pos
mvchgat()stdscrYesNoMoves cursor
wchgat()custom windowYesYesCurrent pos
mvwchgat()custom windowYesYesMoves 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() (or wrefresh()) 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() or wrefresh().
  • 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 every waddch(), 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 like free() 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;
}