forked from xolatile/xhartae
More on curses and program structure...
This commit is contained in:
parent
59fd9b711b
commit
95d48ca3bc
@ -162,14 +162,64 @@ int curses_screen_width = 0;
|
||||
int curses_screen_height = 0;
|
||||
int curses_active = 1;
|
||||
|
||||
static void curses_deinitialize (void) {
|
||||
curses_screen = deallocate (curses_screen);
|
||||
/*
|
||||
I need to quickly explain how I'm structuring this subprogram. You can think of functions and variables starting with 'curses_*' as tiny standalone library if it's easier. They
|
||||
deal with terminal input and output. User only needs to call function 'curses_configure' only once, before doing any rendering, then make an "infinite" loop that'll stop when
|
||||
external variable 'curses_active' is equal to zero. In that loop, user can call any 'curses_render_*' function, and at the end call function 'curses_synchronize' only once. So the
|
||||
following program structure would look something like this:
|
||||
|
||||
@C
|
||||
// ...
|
||||
int main (int argc, char * * argv) {
|
||||
// ...
|
||||
curses_configure ();
|
||||
|
||||
while (curses_active != 0) { // Notice the negative condition, the loop will stop then the condition is 0, so when 'curses_active' is 0.
|
||||
// Calling functions 'curses_render_*' and doing other work...
|
||||
curses_synchronize ();
|
||||
}
|
||||
|
||||
// ...
|
||||
return (0);
|
||||
}
|
||||
@
|
||||
*/
|
||||
|
||||
static void curses_initialize (void) { // This function will be called when 'curses_configure' is called, automatically.
|
||||
struct winsize screen_dimension;
|
||||
|
||||
fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, // If function 'ioctl' failed, we immediately aborting the entire program.
|
||||
"ioctl: Failed to get terminal dimensions."); // I split those error messages, you can find your own formatting style.
|
||||
|
||||
curses_screen_width = (int) screen_dimension.ws_col; // We get the dimensions of terminal window by calling that 'ioctl' function.
|
||||
curses_screen_height = (int) screen_dimension.ws_row;
|
||||
|
||||
fatal_failure (tcgetattr (STDIN_FILENO, & curses_old_terminal) == -1, // Now we need to obtain data for current non-raw terminal to restore it later.
|
||||
"tcgetattr: Failed to get default terminal attributes.");
|
||||
|
||||
curses_new_terminal = curses_old_terminal; // Here we set our raw terminal to be the same as the non-raw one.
|
||||
|
||||
curses_new_terminal.c_cc [VMIN] = (unsigned char) 0;
|
||||
curses_new_terminal.c_cc [VTIME] = (unsigned char) 1;
|
||||
|
||||
curses_new_terminal.c_iflag &= (unsigned int) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); // Now it's time to modify it to be raw, this essentially means no-echo.
|
||||
curses_new_terminal.c_oflag &= (unsigned int) ~(OPOST);
|
||||
curses_new_terminal.c_cflag |= (unsigned int) (CS8);
|
||||
curses_new_terminal.c_lflag &= (unsigned int) ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
|
||||
fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_new_terminal) == -1, // Finally, we're passing intormations to our terminal, and it becomes raw.
|
||||
"tcsetattr: Failed to set reverse terminal attributes.");
|
||||
}
|
||||
|
||||
static void curses_deinitialize (void) { // This function will be only called once, automatically, at the program exit.
|
||||
curses_screen = deallocate (curses_screen); // It's important to deallocate all previously allocated memory.
|
||||
curses_activator = deallocate (curses_activator);
|
||||
curses_action = deallocate (curses_action);
|
||||
|
||||
terminal_clear ();
|
||||
terminal_clear (); // This only make things look prettier, we don't have mess when we exit the program.
|
||||
|
||||
fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_old_terminal) == -1, "tcsetattr: Failed to set default terminal attributes.");
|
||||
fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_old_terminal) == -1, // Again, if this fails, we're doomed, we're aborting.
|
||||
"tcsetattr: Failed to set default terminal attributes.");
|
||||
}
|
||||
|
||||
static char * curses_screen_offset (int x, int y) {
|
||||
@ -223,28 +273,9 @@ External function definitions, those found in "chapter_2.h" header file.
|
||||
*/
|
||||
|
||||
void curses_configure (void) {
|
||||
struct winsize screen_dimension;
|
||||
|
||||
atexit (curses_deinitialize);
|
||||
|
||||
fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, "ioctl: Failed to get terminal dimensions.");
|
||||
|
||||
curses_screen_width = (int) screen_dimension.ws_col;
|
||||
curses_screen_height = (int) screen_dimension.ws_row;
|
||||
|
||||
fatal_failure (tcgetattr (STDIN_FILENO, & curses_old_terminal) == -1, "tcgetattr: Failed to get default terminal attributes.");
|
||||
|
||||
curses_new_terminal = curses_old_terminal;
|
||||
|
||||
curses_new_terminal.c_cc [VMIN] = (unsigned char) 0;
|
||||
curses_new_terminal.c_cc [VTIME] = (unsigned char) 1;
|
||||
|
||||
curses_new_terminal.c_iflag &= (unsigned int) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
curses_new_terminal.c_oflag &= (unsigned int) ~(OPOST);
|
||||
curses_new_terminal.c_cflag |= (unsigned int) (CS8);
|
||||
curses_new_terminal.c_lflag &= (unsigned int) ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
|
||||
fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_new_terminal) == -1, "tcsetattr: Failed to set reverse terminal attributes.");
|
||||
curses_initialize ();
|
||||
|
||||
curses_screen = allocate (CURSES_REVERT + CURSES_FORMAT * curses_screen_width * curses_screen_height + CURSES_CURSOR + 1);
|
||||
|
||||
|
11
xhartae.c
11
xhartae.c
@ -93,13 +93,16 @@ One sane C program should have the following structure (please keep in mind that
|
||||
*/
|
||||
|
||||
int main (int argc, char * * argv) {
|
||||
int i;
|
||||
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
for (i = 0; i != (int) (sizeof (hello_world) / sizeof (* hello_world)); ++i) {
|
||||
hello_world [i] ();
|
||||
curses_configure ();
|
||||
|
||||
while (curses_active != 0) {
|
||||
curses_render_background ('.', COLOUR_GREY, EFFECT_BOLD);
|
||||
curses_render_character ('@', COLOUR_RED, EFFECT_BOLD, 1, 1);
|
||||
|
||||
curses_synchronize ();
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
|
Loading…
Reference in New Issue
Block a user