aboutsummaryrefslogtreecommitdiffstats
path: root/wavemon.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--wavemon.c231
1 files changed, 179 insertions, 52 deletions
diff --git a/wavemon.c b/wavemon.c
index 6c9b689..6c3196e 100644
--- a/wavemon.c
+++ b/wavemon.c
@@ -19,29 +19,96 @@
*/
#include "wavemon.h"
#include <locale.h>
+#include <setjmp.h>
/* GLOBALS */
+
+/**
+ * screen switching table
+ * @key_name: name under which the screen appears in the menu bar
+ * @init: screen initialisation function pointer
+ * @loop: screen update function pointer (connected to menu)
+ * @fini: screen cleanup function pointer
+ */
static const struct {
- char key_name[6];
- enum wavemon_screen (*screen_func)(WINDOW *);
+ const char *const key_name;
+ void (*init)(void);
+ int (*loop)(WINDOW *);
+ void (*fini)(void);
} screens[] = {
- [SCR_INFO] = { "info", scr_info },
- [SCR_LHIST] = { "lhist", scr_lhist },
- [SCR_APLIST] = { "aplst", scr_aplst },
- [SCR_EMPTY_F4] = { "", NULL },
- [SCR_EMPTY_F5] = { "", NULL },
- [SCR_EMPTY_F6] = { "", NULL },
- [SCR_CONF] = { "prefs", scr_conf },
- [SCR_HELP] = { "help", scr_help },
- [SCR_ABOUT] = { "about", scr_about },
- [SCR_QUIT] = { "quit", NULL }
+ [SCR_INFO] = {
+ .key_name = "info",
+ .init = scr_info_init,
+ .loop = scr_info_loop,
+ .fini = scr_info_fini
+ },
+ [SCR_LHIST] = {
+ .key_name = "lhist",
+ .init = scr_lhist_init,
+ .loop = scr_lhist_loop,
+ .fini = scr_lhist_fini
+ },
+ [SCR_APLIST] = {
+ .key_name = "scan",
+ .init = scr_aplst_init,
+ .loop = scr_aplst_loop,
+ .fini = scr_aplst_fini
+ },
+ [SCR_EMPTY_F4] = {
+ .key_name = "",
+ },
+ [SCR_EMPTY_F5] = {
+ .key_name = "",
+ },
+ [SCR_EMPTY_F6] = {
+ .key_name = "",
+ },
+ [SCR_CONF] = {
+ .key_name = "prefs",
+ .init = scr_conf_init,
+ .loop = scr_conf_loop,
+ .fini = scr_conf_fini
+ },
+ [SCR_HELP] = {
+ .key_name = "help",
+ .init = scr_help_init,
+ .loop = scr_help_loop,
+ .fini = scr_help_fini
+ },
+ [SCR_ABOUT] = {
+ .key_name = "about",
+ .init = scr_about_init,
+ .loop = scr_about_loop,
+ .fini = scr_about_fini
+ },
+ [SCR_QUIT] = {
+ .key_name = "quit",
+ }
};
-static void update_menubar(WINDOW *menu, const enum wavemon_screen active)
+/*
+ * SIGWINCH handling with buffer synchronisation variable
+ */
+static sigjmp_buf env_winch;
+static volatile sig_atomic_t env_winch_ready;
+
+static void sig_winch(int signo)
{
+ if (env_winch_ready) {
+ env_winch_ready = false;
+ siglongjmp(env_winch, 1);
+ }
+}
+
+static WINDOW *init_menubar(const enum wavemon_screen active)
+{
+ WINDOW *menu = newwin(1, WAV_WIDTH, WAV_HEIGHT, 0);
enum wavemon_screen cur;
- for (cur = SCR_INFO, wmove(menu, 0, 0); cur <= SCR_QUIT; cur++) {
+ nodelay(menu, TRUE);
+ keypad(menu, TRUE);
+ wmove(menu, 0, 0);
+ for (cur = SCR_INFO; cur <= SCR_QUIT; cur++) {
wattrset(menu, A_REVERSE | A_BOLD);
wprintw(menu, "F%d", cur + 1);
@@ -50,32 +117,35 @@ static void update_menubar(WINDOW *menu, const enum wavemon_screen active)
wprintw(menu, "%-6s", screens[cur].key_name);
}
wrefresh(menu);
+
+ return menu;
}
-static void sig_winch(int signo)
+static void check_geometry(void)
{
- endwin();
- errx(1, "under the pain of death, thou shaltst not resize thyne window");
+ if (conf.check_geometry &&
+ (LINES < MIN_SCREEN_LINES || COLS < MIN_SCREEN_COLS))
+ err_quit("need at least a screen of %ux%u, have only %ux%u",
+ MIN_SCREEN_LINES, MIN_SCREEN_COLS, LINES, COLS);
}
int main(int argc, char *argv[])
{
WINDOW *w_menu;
enum wavemon_screen cur, next;
+ sigset_t blockmask, oldmask;
getconf(argc, argv);
- if (signal(SIGWINCH, sig_winch) == SIG_ERR)
- err(1, "cannot install handler for window changes");
+ if (!isatty(STDIN_FILENO))
+ errx(1, "input is not from a terminal");
/* honour numeric separators if the environment defines them */
setlocale(LC_NUMERIC, "");
/* initialize the ncurses interface */
initscr();
- if (LINES < MIN_SCREEN_LINES || COLS < MIN_SCREEN_COLS)
- err_quit("need at least a screen of %ux%u, have only %ux%u",
- MIN_SCREEN_LINES, MIN_SCREEN_COLS, LINES, COLS);
+ check_geometry();
cbreak();
noecho();
nonl();
@@ -83,36 +153,93 @@ int main(int argc, char *argv[])
curs_set(0);
start_color();
- init_pair(CP_STANDARD, COLOR_WHITE, COLOR_BLACK);
- init_pair(CP_SCALEHI, COLOR_RED, COLOR_BLACK);
- init_pair(CP_SCALEMID, COLOR_YELLOW, COLOR_BLACK);
- init_pair(CP_SCALELOW, COLOR_GREEN, COLOR_BLACK);
- init_pair(CP_WTITLE, COLOR_CYAN, COLOR_BLACK);
- init_pair(CP_INACTIVE, COLOR_CYAN, COLOR_BLACK);
- init_pair(CP_ACTIVE, COLOR_CYAN, COLOR_BLUE);
- init_pair(CP_STATSIG, COLOR_GREEN, COLOR_BLACK);
- init_pair(CP_STATNOISE, COLOR_RED, COLOR_BLACK);
- init_pair(CP_STATSNR, COLOR_BLUE, COLOR_BLUE);
- init_pair(CP_STATBKG, COLOR_BLUE, COLOR_BLACK);
- init_pair(CP_STATSIG_S, COLOR_GREEN, COLOR_BLUE);
- init_pair(CP_STATNOISE_S, COLOR_RED, COLOR_BLUE);
- init_pair(CP_PREF_NORMAL, COLOR_WHITE, COLOR_BLACK);
- init_pair(CP_PREF_SELECT, COLOR_WHITE, COLOR_BLUE);
- init_pair(CP_PREF_ARROW, COLOR_RED, COLOR_BLACK);
-
- w_menu = newwin(1, WAV_WIDTH, WAV_HEIGHT, 0);
- nodelay(w_menu, TRUE);
- keypad(w_menu, TRUE);
-
- for (cur = SCR_HELP, next = conf.startup_scr; next != SCR_QUIT; ) {
-
- if (screens[next].screen_func != NULL)
- cur = next;
-
- reinit_on_changes();
- update_menubar(w_menu, cur);
- next = (*screens[cur].screen_func)(w_menu);
-
+ init_pair(CP_STANDARD, COLOR_WHITE, COLOR_BLACK);
+ init_pair(CP_SCALEHI, COLOR_RED, COLOR_BLACK);
+ init_pair(CP_SCALEMID, COLOR_YELLOW, COLOR_BLACK);
+ init_pair(CP_SCALELOW, COLOR_GREEN, COLOR_BLACK);
+ init_pair(CP_WTITLE, COLOR_CYAN, COLOR_BLACK);
+ init_pair(CP_INACTIVE, COLOR_CYAN, COLOR_BLACK);
+ init_pair(CP_ACTIVE, COLOR_CYAN, COLOR_BLUE);
+
+ init_pair(CP_STATSIG, COLOR_GREEN, COLOR_BLACK);
+ init_pair(CP_STATNOISE, COLOR_RED, COLOR_BLACK);
+ init_pair(CP_STATSNR, COLOR_BLUE, COLOR_BLUE);
+ init_pair(CP_STATBKG, COLOR_BLUE, COLOR_BLACK);
+ init_pair(CP_STATSIG_S, COLOR_GREEN, COLOR_BLUE);
+ init_pair(CP_STATNOISE_S, COLOR_RED, COLOR_BLUE);
+
+ init_pair(CP_PREF_NORMAL, COLOR_WHITE, COLOR_BLACK);
+ init_pair(CP_PREF_SELECT, COLOR_WHITE, COLOR_BLUE);
+ init_pair(CP_PREF_ARROW, COLOR_RED, COLOR_BLACK);
+
+ init_pair(CP_SCAN_CRYPT, COLOR_RED, COLOR_BLACK);
+ init_pair(CP_SCAN_UNENC, COLOR_GREEN, COLOR_BLACK);
+ init_pair(CP_SCAN_NON_AP, COLOR_YELLOW, COLOR_BLACK);
+
+ /* Override signal handlers installed during ncurses initialisation. */
+ xsignal(SIGCHLD, SIG_IGN);
+ xsignal(SIGWINCH, sig_winch); /* triggers only when env_winch_ready */
+ sigemptyset(&blockmask);
+ sigaddset(&blockmask, SIGWINCH);
+
+ for (cur = conf.startup_scr; cur != SCR_QUIT; cur = next) {
+
+ if (sigprocmask(SIG_BLOCK, &blockmask, &oldmask) < 0)
+ err_sys("cannot block SIGWINCH");
+
+ next = cur;
+ w_menu = init_menubar(cur);
+ (*screens[cur].init)();
+
+ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
+ err_sys("cannot unblock SIGWINCH");
+
+ if (sigsetjmp(env_winch, true) == 0) {
+ env_winch_ready = true;
+
+ do {
+ int key = (*screens[cur].loop)(w_menu);
+
+ if (key <= 0)
+ usleep(5000);
+ switch (key) {
+ case KEY_F(1):
+ case KEY_F(2):
+ case KEY_F(3):
+ case KEY_F(7):
+ case KEY_F(8):
+ case KEY_F(9):
+ case KEY_F(10):
+ next = key - KEY_F(1);
+ break;
+ case 'i':
+ next = SCR_INFO;
+ break;
+ case 'q':
+ next = SCR_QUIT;
+ break;
+ default:
+ continue;
+ }
+ } while (next == cur);
+ }
+
+ delwin(w_menu);
+ (*screens[cur].fini)();
+
+ /*
+ * next = cur is set in the protected critical section before
+ * sigsetjmp. Due to the loop condition, it can not occur when
+ * no SIGWINCH occurred, hence it indicates a resizing event.
+ */
+ if (next == cur) {
+ struct winsize size;
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &size) < 0)
+ err_sys("can not determine terminal size");
+ resizeterm(size.ws_row, size.ws_col);
+ check_geometry();
+ }
clear();
refresh();
}