Last active
November 8, 2023 08:53
-
-
Save reagent/9819045 to your computer and use it in GitHub Desktop.
Curses Windowing Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
demo | |
*.swp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ncurses.h> | |
#include <unistd.h> | |
void draw_borders(WINDOW *screen) { | |
int x, y, i; | |
getmaxyx(screen, y, x); | |
// 4 corners | |
mvwprintw(screen, 0, 0, "+"); | |
mvwprintw(screen, y - 1, 0, "+"); | |
mvwprintw(screen, 0, x - 1, "+"); | |
mvwprintw(screen, y - 1, x - 1, "+"); | |
// sides | |
for (i = 1; i < (y - 1); i++) { | |
mvwprintw(screen, i, 0, "|"); | |
mvwprintw(screen, i, x - 1, "|"); | |
} | |
// top and bottom | |
for (i = 1; i < (x - 1); i++) { | |
mvwprintw(screen, 0, i, "-"); | |
mvwprintw(screen, y - 1, i, "-"); | |
} | |
} | |
int main(int argc, char *argv[]) { | |
int parent_x, parent_y, new_x, new_y; | |
int score_size = 3; | |
initscr(); | |
noecho(); | |
curs_set(FALSE); | |
// set up initial windows | |
getmaxyx(stdscr, parent_y, parent_x); | |
WINDOW *field = newwin(parent_y - score_size, parent_x, 0, 0); | |
WINDOW *score = newwin(score_size, parent_x, parent_y - score_size, 0); | |
draw_borders(field); | |
draw_borders(score); | |
while(1) { | |
getmaxyx(stdscr, new_y, new_x); | |
if (new_y != parent_y || new_x != parent_x) { | |
parent_x = new_x; | |
parent_y = new_y; | |
wresize(field, new_y - score_size, new_x); | |
wresize(score, score_size, new_x); | |
mvwin(score, new_y - score_size, 0); | |
wclear(stdscr); | |
wclear(field); | |
wclear(score); | |
draw_borders(field); | |
draw_borders(score); | |
} | |
// draw to our windows | |
mvwprintw(field, 1, 1, "Field"); | |
mvwprintw(score, 1, 1, "Score"); | |
// refresh each window | |
wrefresh(field); | |
wrefresh(score); | |
} | |
endwin(); | |
return 0; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CFLAGS=-Wall | |
LDFLAGS=-lncurses | |
all: demo | |
clean: | |
rm -rf demo |
Would a possible alternative be to handle the signal SIGWINCH
? Ex: this Stack Overflow.
Yes, and that would be much better for the CPU, having a busy while is almost never the answer. @robherley
There is 100% CPU usage because there is no usleep
being used, which is normally common in such loops. You would need it if you're doing any animation.
This version: https://gist.github.com/wmcbrine/f63e83d659cedd5181ae77c56907addb
- Loops at 0% CPU; quits on 'q'.
- Uses box().
- Is compatible with PDCurses as well as ncurses.
There is 100% CPU usage because there is no
usleep
being used, which is normally common in such loops.
While that would be an improvement over the original example, my advice is:
- In a curses-based program, don't use
usleep()
wherenapms()
will suffice.usleep()
introduces a POSIX dependency, whilenapms()
is native to curses, so the app may still be portable to non-POSIX systems. - Don't use
napms()
where a blockinggetch()
will do. Most curses apps will and should spend most of their time in an idle loop waiting on user input, so you may as well letgetch()
do the work of idling. In the case of this example, even resize events are reported as KEY_RESIZE key events by ncurses and PDCurses. And even in cases where a non-blockinggetch()
is needed, you can often rely on mechanisms likehalfdelay()
ortimeout()
instead of resorting to an explicitnapms()
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A possible solution to reduce the CPU load due to while (1):
A timer interrupt for checking "getmaxyx(stdscr, new_y, new_x);"
Though this gist is meant to see the functionality of resizing and not for resource efficiency.
@FuryaevStas: Your comment does help out people to avoid using the re-size logic as-is, in their actual implementation.