diff options
Diffstat (limited to 'src/ui.c')
-rw-r--r-- | src/ui.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/src/ui.c b/src/ui.c new file mode 100644 index 0000000..2fb5a1f --- /dev/null +++ b/src/ui.c @@ -0,0 +1,270 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <string.h> +#include <ncurses.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <mqueue.h> +#include <signal.h> + +#include "ui.h" +#include "ui_ipc.h" +#include "ui_elements.h" +#include "ui_ani.h" +#include "ui_input.h" +#include "ui_statusbar.h" +#include "ui_nwindow.h" + +#include "status.h" +#include "config.h" + +#define APP_TIMEOUT 60 +#define APP_TIMEOUT_FMT "%02d" +#define PASSWD_WIDTH 35 +#define PASSWD_HEIGHT 5 +#define PASSWD_XRELPOS (unsigned int)(PASSWD_WIDTH / 2) - (PASSWD_WIDTH / 6) +#define PASSWD_YRELPOS (unsigned int)(PASSWD_HEIGHT / 2) + 1 +#define INFOWND_WIDTH 25 +#define INFOWND_HEIGHT 3 +#define INFOWND_XRELPOS (unsigned int)(INFOWND_WIDTH / 2) - (INFOWND_WIDTH / 6) +#define INFOWND_YRELPOS (unsigned int)(INFOWND_HEIGHT / 2) + 1 + +#define STRLEN(s) (sizeof(s)/sizeof(s[0])) + + +static unsigned int max_x, max_y; +static WINDOW *wnd_main; +static struct nask_ui /* simple linked list to all UI objects */ *nui = NULL, + /* current active input */ *active = NULL; +static pthread_t thrd; +static unsigned int atmout = APP_TIMEOUT; +static pthread_cond_t cnd_update = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mtx_update = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t mtx_busy = PTHREAD_MUTEX_INITIALIZER; + + +void +register_ui_elt(struct ui_callbacks *cbs, void *data, WINDOW *wnd) +{ + struct nask_ui *tmp, *new; + + new = calloc(1, sizeof(struct nask_ui)); + new->cbs = *cbs; + new->wnd = wnd; + new->data = data; + new->next = NULL; + if (nui == NULL) { + nui = new; + nui->next = NULL; + } else { + tmp = nui; + while (tmp->next != NULL) { + tmp = tmp->next; + } + tmp->next = new; + } +} + +void +unregister_ui_elt(void *data) +{ + struct nask_ui *cur, *next, *before = NULL; + + cur = nui; + while (cur != NULL) { + next = cur->next; + if (cur->data != NULL && cur->data == data) { + free(cur); + if (before != NULL) { + before->next = next; + } else { + nui = next; + } + } + before = cur; + cur = next; + } +} + +int +activate_ui_input(void *data) +{ + struct nask_ui *cur = nui; + + if (cur == NULL || data == NULL) return DOUI_NINIT; + while ( cur->data != NULL ) { + if ( cur->data == data ) { + if ( cur->cbs.ui_input != NULL && cur->cbs.ui_input(cur->wnd, data, UIKEY_ACTIVATE) == DOUI_OK ) { + active = cur; + return DOUI_OK; + } + } + cur = cur->next; + } + return DOUI_ERR; +} + +int +reactivate_ui_input(void) +{ + if (active) { + if (active->cbs.ui_element) { + } + return ( active->cbs.ui_input(active->wnd, active->data, UIKEY_ACTIVATE) ); + } else return DOUI_ERR; +} + +static bool +process_key(char key) +{ + atmout = APP_TIMEOUT; + if ( active != NULL ) { + return ( active->cbs.ui_input(active->wnd, active->data, key) == DOUI_OK ? true : false ); + } + return false; +} + +static int +do_ui_update(bool timed_out) +{ + int retval = UICB_OK; + int curx = getcurx(wnd_main); + int cury = getcury(wnd_main); + struct nask_ui *cur = nui; + + /* call all draw callback's */ + erase(); + while (cur != NULL) { + if (cur->cbs.ui_element != NULL) { + cur->cbs.ui_element(cur->wnd, cur->data, timed_out); + doupdate(); + } else { + retval = UICB_ERR_CB; + } + cur = cur->next; + } + /* TODO: Maybe export to an extra module? */ + attron(COLOR_PAIR(1)); + mvprintw(0, max_x - STRLEN(APP_TIMEOUT_FMT), "[" APP_TIMEOUT_FMT "]", atmout); + attroff(COLOR_PAIR(1)); + /* EoT (End of Todo) */ + wmove(wnd_main, cury, curx); + wrefresh(wnd_main); + return (retval); +} + +static void * +ui_thrd(void *arg) +{ + int cnd_ret; + struct timeval now; + struct timespec wait; + + gettimeofday(&now, NULL); + wait.tv_sec = now.tv_sec + UILOOP_TIMEOUT; + wait.tv_nsec = now.tv_usec * 1000; + do_ui_update(true); + ui_ipc_sempost(SEM_RD); + pthread_mutex_lock(&mtx_update); + while ( ui_ipc_getvalue(SEM_UI) > 0 ) { + pthread_mutex_unlock(&mtx_busy); + cnd_ret = pthread_cond_timedwait(&cnd_update, &mtx_update, &wait); + pthread_mutex_lock(&mtx_busy); + if (--atmout == 0) ui_ipc_semtrywait(SEM_UI); + do_ui_update( (cnd_ret == ETIMEDOUT ? true : false) ); + if (cnd_ret == ETIMEDOUT) { + wait.tv_sec += UILOOP_TIMEOUT; + } + } + pthread_mutex_unlock(&mtx_update); + return (NULL); +} + +void +ui_thrd_force_update(void) +{ + pthread_mutex_lock(&mtx_busy); + pthread_cond_signal(&cnd_update); + pthread_mutex_unlock(&mtx_busy); +} + +WINDOW * +init_ui(void) +{ + wnd_main = initscr(); + max_x = getmaxx(wnd_main); + max_y = getmaxy(wnd_main); + start_color(); + init_pair(1, COLOR_RED, COLOR_WHITE); + init_pair(2, COLOR_WHITE, COLOR_BLACK); + init_pair(3, COLOR_BLACK, COLOR_WHITE); + init_pair(4, COLOR_YELLOW, COLOR_RED); + raw(); + keypad(stdscr, TRUE); + noecho(); + cbreak(); + return (wnd_main); +} + +void +free_ui(void) +{ + delwin(wnd_main); + endwin(); + clear(); + printf(" \033[2J\n"); +} + +static int +run_ui_thrd(void) { + return (pthread_create(&thrd, NULL, &ui_thrd, NULL)); +} + +static int +stop_ui_thrd(void) +{ + return (pthread_join(thrd, NULL)); +} + +int +do_ui(void) +{ + char key = '\0'; + int ret = DOUI_ERR; + + /* init TUI and UI Elements (input field, status bar, etc) */ + init_ui(); + init_ui_elements(wnd_main, max_x, max_y); + + pthread_mutex_lock(&mtx_update); + if (run_ui_thrd() != 0) { + return ret; + } + ui_ipc_semwait(SEM_RD); + wtimeout(wnd_main, 1000); + pthread_mutex_unlock(&mtx_update); + while ( ui_ipc_getvalue(SEM_UI) > 0 ) { + if ((key = wgetch(wnd_main)) == '\0') { + break; + } + if (key == -1) { + continue; + } + if ( process_key(key) != true ) { + ui_ipc_semtrywait(SEM_UI); + ui_thrd_force_update(); + } + } + stop_ui_thrd(); + free_ui_elements(); + + return DOUI_OK; +} + |