aboutsummaryrefslogtreecommitdiff
path: root/display.c
diff options
context:
space:
mode:
Diffstat (limited to 'display.c')
-rw-r--r--display.c703
1 files changed, 516 insertions, 187 deletions
diff --git a/display.c b/display.c
index d3ec421..f06387c 100644
--- a/display.c
+++ b/display.c
@@ -13,261 +13,590 @@
* - initial API and implementation
*******************************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <ncurses.h>
+#include <sys/types.h>
+#include <regex.h>
#include "powerdebug.h"
+#include "mainloop.h"
#include "regulator.h"
#include "display.h"
-#define print(w, x, y, fmt, args...) do { mvwprintw(w, y, x, fmt, ##args); } while (0)
-#define NUM_FOOTER_ITEMS 5
+enum { PT_COLOR_DEFAULT = 1,
+ PT_COLOR_HEADER_BAR,
+ PT_COLOR_ERROR,
+ PT_COLOR_RED,
+ PT_COLOR_YELLOW,
+ PT_COLOR_GREEN,
+ PT_COLOR_BRIGHT,
+ PT_COLOR_BLUE,
+};
static WINDOW *header_win;
-static WINDOW *regulator_win;
-static WINDOW *clock_win;
-static WINDOW *sensor_win;
-static WINDOW *selected_win;
static WINDOW *footer_win;
+static WINDOW *main_win;
+static int current_win;
+
+/* Number of lines in the virtual window */
+static const int maxrows = 1024;
+
+struct rowdata {
+ int attr;
+ void *data;
+};
+
+struct windata {
+ WINDOW *pad;
+ struct display_ops *ops;
+ struct rowdata *rowdata;
+ char *name;
+ int nrdata;
+ int scrolling;
+ int cursor;
+};
+
+/* Warning this is linked with the enum { CLOCK, REGULATOR, ... } */
+struct windata windata[] = {
+ [CLOCK] = { .name = "Clocks" },
+ [REGULATOR] = { .name = "Regulators" },
+ [SENSOR] = { .name = "Sensors" },
+ [GPIO] = { .name = "Gpio" },
+};
+
+static void display_fini(void)
+{
+ endwin();
+}
+
+static int display_show_header(int win)
+{
+ int i;
+ int curr_pointer = 0;
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
-int maxx, maxy;
-char footer_items[NUM_FOOTER_ITEMS][64];
+ wattrset(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
+ wbkgd(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
+ werase(header_win);
+ mvwprintw(header_win, 0, curr_pointer, "PowerDebug %s", VERSION);
+ curr_pointer += 20;
-void fini_curses(void) {
- endwin();
+ for (i = 0; i < array_size; i++) {
+ if (win == i)
+ wattron(header_win, A_REVERSE);
+ else
+ wattroff(header_win, A_REVERSE);
+
+ mvwprintw(header_win, 0, curr_pointer, " %s ", windata[i].name);
+ curr_pointer += strlen(windata[i].name) + 2;
+ }
+ wrefresh(header_win);
+
+ return 0;
}
-/* "all" : Kill header and footer windows too ? */
-void killall_windows(int all)
+#define footer_label " Q (Quit) R (Refresh) Other Keys: 'Left', " \
+ "'Right' , 'Up', 'Down', 'enter', , 'Esc'"
+
+static int display_show_footer(int win, char *string)
{
- if (all && header_win) {
- delwin(header_win);
- header_win = NULL;
- }
- if (regulator_win) {
- delwin(regulator_win);
- regulator_win = NULL;
- }
- if (clock_win) {
- delwin(clock_win);
- clock_win = NULL;
+ werase(footer_win);
+ wattron(footer_win, A_REVERSE);
+ mvwprintw(footer_win, 0, 0, "%s", string ? string : footer_label);
+ wattroff(footer_win, A_REVERSE);
+ wrefresh(footer_win);
+
+ return 0;
+}
+
+static int display_refresh(int win, bool read)
+{
+ /* we are trying to refresh a window which is not showed */
+ if (win != current_win)
+ return 0;
+
+ if (windata[win].ops && windata[win].ops->display)
+ return windata[win].ops->display(read);
+
+ if (werase(main_win))
+ return -1;
+
+ return wrefresh(main_win);
+}
+
+int display_refresh_pad(int win)
+{
+ int maxx, maxy;
+
+ getmaxyx(stdscr, maxy, maxx);
+
+ return prefresh(windata[win].pad, windata[win].scrolling,
+ 0, 2, 0, maxy - 2, maxx);
+}
+
+static int display_show_unselection(int win, int line, bool bold)
+{
+ if (mvwchgat(windata[win].pad, line, 0, -1,
+ bold ? WA_BOLD: WA_NORMAL, 0, NULL) < 0)
+ return -1;
+
+ return display_refresh_pad(win);
+}
+
+void *display_get_row_data(int win)
+{
+ return windata[win].rowdata[windata[win].cursor].data;
+}
+
+static int display_select(void)
+{
+ if (windata[current_win].ops && windata[current_win].ops->select)
+ return windata[current_win].ops->select();
+
+ return 0;
+}
+
+static int display_next_panel(void)
+{
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+ current_win++;
+ current_win %= array_size;
+
+ return current_win;
+}
+
+static int display_prev_panel(void)
+{
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+ current_win--;
+ if (current_win < 0)
+ current_win = array_size - 1;
+
+ return current_win;
+}
+
+static int display_next_line(void)
+{
+ int maxx, maxy;
+ int cursor = windata[current_win].cursor;
+ int nrdata = windata[current_win].nrdata;
+ int scrolling = windata[current_win].scrolling;
+ struct rowdata *rowdata = windata[current_win].rowdata;
+
+ getmaxyx(stdscr, maxy, maxx);
+
+ if (cursor >= nrdata)
+ return cursor;
+
+ display_show_unselection(current_win, cursor, rowdata[cursor].attr);
+ if (cursor < nrdata - 1) {
+ if (cursor >= (maxy - 4 + scrolling))
+ scrolling++;
+ cursor++;
}
- if (sensor_win) {
- delwin(sensor_win);
- sensor_win = NULL;
+
+ windata[current_win].scrolling = scrolling;
+ windata[current_win].cursor = cursor;
+
+ return cursor;
+}
+
+static int display_prev_line(void)
+{
+ int cursor = windata[current_win].cursor;
+ int nrdata = windata[current_win].nrdata;
+ int scrolling = windata[current_win].scrolling;
+ struct rowdata *rowdata = windata[current_win].rowdata;
+
+ if (cursor >= nrdata)
+ return cursor;
+
+ display_show_unselection(current_win, cursor, rowdata[cursor].attr);
+ if (cursor > 0) {
+ if (cursor <= scrolling)
+ scrolling--;
+ cursor--;
}
- if (all && footer_win) {
- delwin(footer_win);
- footer_win = NULL;
+
+ windata[current_win].scrolling = scrolling;
+ windata[current_win].cursor = cursor;
+
+ return cursor;
+}
+
+static int display_set_row_data(int win, int line, void *data, int attr)
+{
+ struct rowdata *rowdata = windata[win].rowdata;
+
+ if (line >= windata[win].nrdata) {
+ rowdata = realloc(rowdata, sizeof(struct rowdata) * (line + 1));
+ if (!rowdata)
+ return -1;
+ windata[win].nrdata = line + 1;
}
+
+ rowdata[line].data = data;
+ rowdata[line].attr = attr;
+ windata[win].rowdata = rowdata;
+
+ return 0;
}
-void init_curses(void)
+int display_reset_cursor(int win)
{
- initscr();
- start_color();
- keypad(stdscr, TRUE);
- noecho();
- cbreak();
- curs_set(0);
- nonl();
- use_default_colors();
+ windata[win].nrdata = 0;
+ werase(windata[win].pad);
+ return wmove(windata[win].pad, 0, 0);
+}
+
+int display_print_line(int win, int line, char *str, int bold, void *data)
+{
+ int attr = 0;
+
+ if (bold)
+ attr |= WA_BOLD;
+
+ if (line == windata[win].cursor)
+ attr |= WA_STANDOUT;
- init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
- init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
- init_pair(PT_COLOR_HEADER_BAR, COLOR_WHITE, COLOR_BLACK);
- init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
- init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
- init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
- init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
- init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
+ if (display_set_row_data(win, line, data, attr))
+ return -1;
- atexit(fini_curses);
+ if (attr)
+ wattron(windata[win].pad, attr);
+
+ wprintw(windata[win].pad, "%s\n", str);
+
+ if (attr)
+ wattroff(windata[win].pad, attr);
+
+ return 0;
}
+static int display_find_keystroke(int fd, void *data);
-void create_windows(void)
+struct find_data {
+ size_t len;
+ char *string;
+ regex_t *reg;
+ int ocursor;
+ int oscrolling;
+};
+
+struct find_data *display_find_init(void)
{
+ const char *regexp = "^[a-z|0-9|_|-|.]";
+ struct find_data *findd;
+ const size_t len = 64;
+ regex_t *reg;
+ char *search4;
+ int maxx, maxy;
getmaxyx(stdscr, maxy, maxx);
- killall_windows(1);
- header_win = subwin(stdscr, 1, maxx, 0, 0);
- footer_win = subwin(stdscr, 1, maxx, maxy-1, 0);
+ reg = malloc(sizeof(*reg));
+ if (!reg)
+ return NULL;
- strcpy(footer_items[0], " Q (Quit) ");
- strcpy(footer_items[1], " R (Refresh) ");
+ if (regcomp(reg, regexp, REG_ICASE))
+ goto out_free_reg;
- if (selectedwindow == CLOCK)
- strcpy(footer_items[2], " Other Keys: 'Left', 'Right', 'Up', 'Down', 'enter', "
- " '/', 'Esc' ");
- else
- strcpy(footer_items[2], " Other Keys: 'Left', 'Right' ");
+ search4 = malloc(len);
+ if (!search4)
+ goto out_free_regcomp;
+ memset(search4, '\0', len);
- strcpy(footer_items[3], "");
+ findd = malloc(sizeof(*findd));
+ if (!findd)
+ goto out_free_search4;
- werase(stdscr);
- refresh();
+ findd->string = search4;
+ findd->reg = reg;
+ findd->len = len;
+ /* save the location of the cursor on the main window in order to
+ * browse the search result
+ */
+ findd->ocursor = windata[current_win].cursor;
+ findd->oscrolling = windata[current_win].scrolling;
+
+ windata[current_win].cursor = 0;
+ windata[current_win].scrolling = 0;
+
+ curs_set(1);
+out:
+ return findd;
+
+out_free_search4:
+ free(search4);
+out_free_regcomp:
+ regfree(reg);
+out_free_reg:
+ free(reg);
+
+ goto out;
+}
+
+static void display_find_fini(struct find_data *findd)
+{
+ windata[current_win].cursor = findd->ocursor;
+ windata[current_win].scrolling = findd->oscrolling;
+ regfree(findd->reg);
+ free(findd->string);
+ free(findd);
+ curs_set(0);
}
-void create_selectedwindow(void)
+static int display_switch_to_find(int fd)
{
- WINDOW *win;
+ struct find_data *findd;
- killall_windows(0);
+ findd = display_find_init();
+ if (!findd)
+ return -1;
- getmaxyx(stdscr, maxy, maxx);
+ if (mainloop_del(fd))
+ return -1;
+
+ if (mainloop_add(fd, display_find_keystroke, findd))
+ return -1;
+
+ if (display_show_footer(current_win, "find (esc to exit)?"))
+ return -1;
+
+ return 0;
+}
+
+static int display_keystroke(int fd, void *data)
+{
+ int keystroke = getch();
+
+ switch (keystroke) {
+
+ case KEY_RIGHT:
+ case '\t':
+ display_show_header(display_next_panel());
+ break;
- win = subwin(stdscr, maxy - 2, maxx, 1, 0);
+ case KEY_LEFT:
+ case KEY_BTAB:
+ display_show_header(display_prev_panel());
+ break;
- switch (selectedwindow) {
- case REGULATOR: regulator_win = win;
+ case KEY_DOWN:
+ display_next_line();
break;
- case CLOCK: clock_win = win;
+ case KEY_UP:
+ display_prev_line();
break;
- case SENSOR: sensor_win = win;
+ case '\r':
+ display_select();
break;
+
+ case EOF:
+ case 'q':
+ case 'Q':
+ return 1;
+
+ case '/':
+ return display_switch_to_find(fd);
+
+ case 'r':
+ case 'R':
+ return display_refresh(current_win, true);
+ default:
+ return 0;
}
- selected_win = win;
+ display_refresh(current_win, false);
- refresh();
+ return 0;
}
-void show_header(void)
+static int display_switch_to_main(int fd)
{
- int i, j = 0;
- int curr_pointer = 0;
+ if (mainloop_del(fd))
+ return -1;
- wattrset(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
- wbkgd(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
- werase(header_win);
+ if (mainloop_add(fd, display_keystroke, NULL))
+ return -1;
- print(header_win, curr_pointer, 0, "PowerDebug %s", VERSION);
- curr_pointer += 20;
+ if (display_show_header(current_win))
+ return -1;
- for (i = 0; i < TOTAL_FEATURE_WINS; i++) {
- if (selectedwindow == i)
- wattron(header_win, A_REVERSE);
- else
- wattroff(header_win, A_REVERSE);
+ if (display_show_footer(current_win, NULL))
+ return -1;
- print(header_win, curr_pointer, 0, " %s ", win_names[i]);
- curr_pointer += strlen(win_names[i]) + 2;
- }
- wrefresh(header_win);
- werase(footer_win);
+ return display_refresh(current_win, false);
+}
+
+static int display_find_keystroke(int fd, void *data)
+{
+ struct find_data *findd = data;
+ regex_t *reg = findd->reg;
+ char *string = findd->string;
+ int keystroke = getch();
+ char match[2] = { [0] = (char)keystroke, [1] = '\0' };
+ regmatch_t m[1];
+
+ switch (keystroke) {
+
+ case '\e':
+ display_find_fini(findd);
+ return display_switch_to_main(fd);
+
+ case KEY_DOWN:
+ display_next_line();
+ break;
+
+ case KEY_UP:
+ display_prev_line();
+ break;
+
+ case KEY_BACKSPACE:
+ if (strlen(string))
+ string[strlen(string) - 1] = '\0';
+
+ windata[current_win].cursor = 0;
+ windata[current_win].scrolling = 0;
+
+ break;
+
+ case '\r':
+ if (!windata[current_win].ops || !windata[current_win].ops->selectf)
+ return 0;
+
+ if (windata[current_win].ops->selectf())
+ return -1;
- for (i = 0; i < NUM_FOOTER_ITEMS; i++) {
- if (strlen(footer_items[i]) == 0)
- continue;
- wattron(footer_win, A_REVERSE);
- print(footer_win, j, 0, "%s", footer_items[i]);
- wattroff(footer_win, A_REVERSE);
- j+= strlen(footer_items[i])+1;
+ windata[current_win].cursor = 0;
+ windata[current_win].scrolling = 0;
+
+ return 0;
+
+ default:
+
+ /* We don't want invalid characters for a name */
+ if (regexec(reg, match, 1, m, 0))
+ return 0;
+
+ if (strlen(string) < findd->len - 1)
+ string[strlen(string)] = (char)keystroke;
+
+ windata[current_win].cursor = 0;
+ windata[current_win].scrolling = 0;
+
+ break;
}
- wrefresh(footer_win);
-}
+ if (!windata[current_win].ops || !windata[current_win].ops->find)
+ return 0;
+
+ if (windata[current_win].ops->find(string))
+ return -1;
+
+ if (display_show_header(current_win))
+ return -1;
+
+ if (display_show_footer(current_win, strlen(string) ? string :
+ "find (esc to exit)?"))
+ return -1;
-void show_regulator_info(int verbose)
+ return 0;
+}
+
+int display_init(int wdefault)
{
- int i, count = 1;
-
- (void)verbose;
-
- werase(regulator_win);
- wattron(regulator_win, A_BOLD);
- print(regulator_win, 0, 0, "Name");
- print(regulator_win, 12, 0, "Status");
- print(regulator_win, 24, 0, "State");
- print(regulator_win, 36, 0, "Type");
- print(regulator_win, 48, 0, "Users");
- print(regulator_win, 60, 0, "Microvolts");
- print(regulator_win, 72, 0, "Min u-volts");
- print(regulator_win, 84, 0, "Max u-volts");
- wattroff(regulator_win, A_BOLD);
-
- for (i = 0; i < numregulators; i++) {
- int col = 0;
-
- if ((i + 2) > (maxy-2))
- break;
-
- if (regulators_info[i].num_users > 0)
- wattron(regulator_win, WA_BOLD);
- else
- wattroff(regulator_win, WA_BOLD);
-
- print(regulator_win, col, count, "%s",
- regulators_info[i].name);
- col += 12;
- print(regulator_win, col, count, "%s",
- regulators_info[i].status);
- col += 12;
- print(regulator_win, col, count, "%s",
- regulators_info[i].state);
- col += 12;
- print(regulator_win, col, count, "%s",
- regulators_info[i].type);
- col += 12;
- print(regulator_win, col, count, "%d",
- regulators_info[i].num_users);
- col += 12;
- print(regulator_win, col, count, "%d",
- regulators_info[i].microvolts);
- col += 12;
- print(regulator_win, col, count, "%d",
- regulators_info[i].min_microvolts);
- col += 12;
- print(regulator_win, col, count, "%d",
- regulators_info[i].max_microvolts);
-
- count++;
+ int i, maxx, maxy;
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+ current_win = wdefault;
+
+ if (mainloop_add(0, display_keystroke, NULL))
+ return -1;
+
+ if (!initscr())
+ return -1;
+
+ start_color();
+ use_default_colors();
+
+ keypad(stdscr, TRUE);
+ noecho();
+ cbreak();
+ curs_set(0);
+ nonl();
+
+ if (init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK) ||
+ init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED) ||
+ init_pair(PT_COLOR_HEADER_BAR, COLOR_WHITE, COLOR_BLACK) ||
+ init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW) ||
+ init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN) ||
+ init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK) ||
+ init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE) ||
+ init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED))
+ return -1;
+
+ if (atexit(display_fini))
+ return -1;
+
+ getmaxyx(stdscr, maxy, maxx);
+
+ for (i = 0; i < array_size; i++) {
+
+ main_win = subwin(stdscr, maxy - 2, maxx, 1, 0);
+ if (!main_win)
+ return -1;
+
+ windata[i].pad = newpad(maxrows, maxx);
+ if (!windata[i].pad)
+ return -1;
+
}
- wrefresh(regulator_win);
-}
+ header_win = subwin(stdscr, 1, maxx, 0, 0);
+ if (!header_win)
+ return -1;
-void print_clock_header(void)
-{
- werase(clock_win);
- wattron(clock_win, A_BOLD);
- print(clock_win, 0, 0, "Name");
- print(clock_win, 54, 0, "Flags");
- print(clock_win, 64, 0, "Rate");
- print(clock_win, 72, 0, "Usecount");
- print(clock_win, 84, 0, "Children");
- wattroff(clock_win, A_BOLD);
- wrefresh(clock_win);
+ footer_win = subwin(stdscr, 1, maxx, maxy-1, 0);
+ if (!footer_win)
+ return -1;
+
+ if (display_show_header(wdefault))
+ return -1;
+
+ if (display_show_footer(wdefault, NULL))
+ return -1;
+
+ return display_refresh(wdefault, true);
}
-void print_sensor_header(void)
+int display_column_name(const char *line)
{
- werase(sensor_win);
- wattron(sensor_win, A_BOLD);
- print(sensor_win, 0, 0, "Name");
- print(sensor_win, 36, 0, "Temperature");
- wattroff(sensor_win, A_BOLD);
- wattron(sensor_win, A_BLINK);
- print(sensor_win, 0, 1, "Currently Sensor information available"
- " only in Dump mode!");
- wattroff(sensor_win, A_BLINK);
- wrefresh(sensor_win);
+ werase(main_win);
+ wattron(main_win, A_BOLD);
+ mvwprintw(main_win, 0, 0, "%s", line);
+ wattroff(main_win, A_BOLD);
+ wrefresh(main_win);
+
+ return 0;
}
-void print_one_clock(int line, char *str, int bold, int highlight)
+int display_register(int win, struct display_ops *ops)
{
- if (bold)
- wattron(clock_win, WA_BOLD);
- if (highlight)
- wattron(clock_win, WA_STANDOUT);
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
- print(clock_win, 0, line + 1, "%s", str);
- if (bold)
- wattroff(clock_win, WA_BOLD);
- if (highlight)
- wattroff(clock_win, WA_STANDOUT);
- wrefresh(clock_win);
+ if (win < 0 || win >= array_size)
+ return -1;
+
+ windata[win].ops = ops;
+
+ return 0;
}