Annotation of embedaddon/bmon/src/out_curses.c, revision 1.1.1.1
1.1 misho 1: /*
2: * out_curses.c Curses Output
3: *
4: * Copyright (c) 2001-2005 Thomas Graf <tgraf@suug.ch>
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a
7: * copy of this software and associated documentation files (the "Software"),
8: * to deal in the Software without restriction, including without limitation
9: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10: * and/or sell copies of the Software, and to permit persons to whom the
11: * Software is furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included
14: * in all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22: * DEALINGS IN THE SOFTWARE.
23: */
24:
25: #include <bmon/bmon.h>
26: #include <bmon/graph.h>
27: #include <bmon/conf.h>
28: #include <bmon/itemtab.h>
29: #include <bmon/input.h>
30: #include <bmon/output.h>
31: #include <bmon/node.h>
32: #include <bmon/bindings.h>
33: #include <bmon/utils.h>
34:
35: static int initialized;
36: static int print_help = 0;
37: static int quit_mode = 0;
38: static int help_page = 0;
39: static int row;
40: static int rows;
41: static int cols;
42:
43: static int c_graph_height = 6;
44: static int c_use_colors = 1;
45: static int c_combined_node_list = 0;
46: static int c_graphical_in_list = 0;
47: static int c_detailed_in_list = 0;
48: static int c_list_in_list = 1;
49: static int c_nototal = 0;
50: static int c_nosource = 0;
51:
52: #define NEXT_ROW { \
53: row++; \
54: if (row >= rows-1) \
55: return; \
56: move(row,0); \
57: }
58:
59: static void putl(const char *fmt, ...)
60: {
61: va_list args;
62: char buf[2048];
63: int x, y;
64:
65: memset(buf, 0, sizeof(buf));
66: getyx(stdscr, y, x);
67:
68: va_start(args, fmt);
69: vsnprintf(buf, sizeof(buf), fmt, args);
70: va_end(args);
71:
72: if (strlen(buf) > cols-x)
73: buf[cols-x] = '\0';
74: else
75: memset(&buf[strlen(buf)], ' ', cols-strlen(buf)-x);
76:
77: addstr(buf);
78: }
79:
80: static void curses_init(void)
81: {
82: if (!initscr())
83: exit(1);
84:
85: initialized = 1;
86:
87: if (!has_colors())
88: c_use_colors = 0;
89:
90: if (c_use_colors) {
91: int i;
92:
93: start_color();
94:
95: #if defined HAVE_USE_DEFAULT_COLORS
96: use_default_colors();
97: #endif
98: for (i = 1; i < NR_LAYOUTS+1; i++)
99: init_pair(i, layout[i].fg, layout[i].bg);
100: }
101:
102: keypad(stdscr, TRUE);
103: nonl();
104: cbreak();
105: noecho();
106: nodelay(stdscr, TRUE); /* getch etc. must be non-blocking */
107: clear();
108: curs_set(0);
109: }
110:
111: static void curses_shutdown(void)
112: {
113: if (initialized)
114: endwin();
115: }
116:
117: static void draw_item_list_entry(item_t *intf, node_t *node)
118: {
119: int rxprec, txprec, rxpprec, txpprec;
120: stat_attr_t *bytes, *packets;
121: double rx, tx, rxp, txp;
122: char *rx_u, *tx_u, *rxp_u, *txp_u;
123: char pad[23];
124:
125: bytes = lookup_attr(intf, intf->i_major_attr);
126: packets = lookup_attr(intf, intf->i_minor_attr);
127:
128: if (bytes == NULL || packets == NULL)
129: return;
130:
131: rx = cancel_down(attr_get_rx_rate(bytes), bytes->a_unit, &rx_u, &rxprec);
132: tx = cancel_down(attr_get_tx_rate(bytes), bytes->a_unit, &tx_u, &txprec);
133:
134: rxp = cancel_down(attr_get_rx_rate(packets), packets->a_unit, &rxp_u, &rxpprec);
135: txp = cancel_down(attr_get_tx_rate(packets), packets->a_unit, &txp_u, &txpprec);
136:
137: memset(pad, 0, sizeof(pad));
138: memset(pad, ' ', intf->i_level < 15 ? intf->i_level : 15);
139:
140: strncat(pad, intf->i_name, sizeof(pad) - strlen(pad) - 1);
141:
142: if (intf->i_desc) {
143: strncat(pad, " (", sizeof(pad) - strlen(pad) - 1);
144: strncat(pad, intf->i_desc, sizeof(pad) - strlen(pad) - 1);
145: strncat(pad, ")", sizeof(pad) - strlen(pad) - 1);
146: }
147: NEXT_ROW;
148:
149: if (intf->i_index == node->n_selected && node == get_current_node()) {
150: if (c_use_colors)
151: attrset(COLOR_PAIR(LAYOUT_SELECTED) | layout[LAYOUT_SELECTED].attr);
152: else
153: attron(A_REVERSE);
154: }
155:
156: printw(" %-3d%s", intf->i_index, (intf->i_flags & ITEM_FLAG_FOLDED) ? "+" : " ");
157:
158: if (intf->i_index == node->n_selected && node == get_current_node()) {
159: if (c_use_colors)
160: attrset(COLOR_PAIR(LAYOUT_LIST) | layout[LAYOUT_LIST].attr);
161: else
162: attroff(A_REVERSE);
163: }
164:
165: putl("%-22s %8.*f%s %8.*f%s %2d%% %8.*f%s %8.*f%s %2d%%", pad,
166: rxprec, rx, rx_u, rxpprec, rxp, rxp_u, intf->i_rx_usage,
167: txprec, tx, tx_u, txpprec, txp, txp_u, intf->i_tx_usage);
168:
169: if (intf->i_rx_usage == -1) {
170: move(row, 51);
171: addstr(" ");
172: }
173:
174: if (intf->i_tx_usage == -1) {
175: move(row, 77);
176: addstr(" ");
177: }
178:
179: move(row, 28);
180: addch(ACS_VLINE);
181: move(row, 54);
182: addch(ACS_VLINE);
183: }
184:
185: static void handle_child(item_t *intf, void *arg)
186: {
187: node_t *node = arg;
188:
189: draw_item_list_entry(intf, node);
190: foreach_child(node, intf, handle_child, node);
191: }
192:
193:
194: static void draw_item(node_t *node, item_t *intf)
195: {
196: if (!intf->i_name[0] || row >= (rows - 1) || (intf->i_flags & ITEM_FLAG_IS_CHILD))
197: return;
198:
199: draw_item_list_entry(intf, node);
200:
201: if (!(intf->i_flags & ITEM_FLAG_FOLDED))
202: foreach_child(node, intf, handle_child, node);
203: }
204:
205:
206: static void draw_node(node_t *node, void *arg)
207: {
208: int i, *cnt = (int *) arg;
209:
210: if (cnt) {
211: if (*cnt) {
212: int n;
213: NEXT_ROW;
214: for (n = 1; n < cols; n += 2)
215: mvaddch(row, n, ACS_HLINE);
216: move(row, 28);
217: addch(ACS_VLINE);
218: move(row, 54);
219: addch(ACS_VLINE);
220: }
221: (*cnt)++;
222: }
223:
224: attrset(A_BOLD);
225: NEXT_ROW;
226: if (c_nosource)
227: putl("%s", node->n_name);
228: else
229: putl("%s (%s)", node->n_name,
230: node->n_from ? node->n_from : "local");
231:
232: move(row, 30);
233: putl(" Rate # %% Rate # %%");
234: attroff(A_BOLD);
235:
236: move(row, 28);
237: addch(ACS_VLINE);
238: move(row, 54);
239: addch(ACS_VLINE);
240:
241: if (c_use_colors)
242: attrset(COLOR_PAIR(LAYOUT_LIST) | layout[LAYOUT_LIST].attr);
243:
244: for (i = 0; i < node->n_nitems; i++)
245: draw_item(node, &node->n_items[i]);
246:
247: if (!c_nototal) {
248: int rx_maj_prec, tx_maj_prec, rx_min_prec, tx_min_prec;
249: double rx_maj, tx_maj, rx_min, tx_min;
250: char *rx_maj_u, *tx_maj_u, *rx_min_u, *tx_min_u;
251:
252: rx_maj = cancel_down(node->n_rx_maj_total, U_BYTES, &rx_maj_u, &rx_maj_prec);
253: tx_maj = cancel_down(node->n_tx_maj_total, U_BYTES, &tx_maj_u, &tx_maj_prec);
254:
255: rx_min = cancel_down(node->n_rx_min_total, U_NUMBER, &rx_min_u, &rx_min_prec);
256: tx_min = cancel_down(node->n_tx_min_total, U_NUMBER, &tx_min_u, &tx_min_prec);
257:
258: NEXT_ROW;
259: putl(" %-26s %8.*f%s %8.*f%s %8.*f%s %8.*f%s ", "Total",
260: rx_maj_prec, rx_maj, rx_maj_u, rx_min_prec, rx_min, rx_min_u,
261: tx_maj_prec, tx_maj, tx_maj_u, tx_min_prec, tx_min, tx_min_u);
262:
263: move(row, 28);
264: addch(ACS_VLINE);
265: move(row, 54);
266: addch(ACS_VLINE);
267: }
268:
269: if (c_use_colors)
270: attrset(COLOR_PAIR(LAYOUT_DEFAULT) | layout[LAYOUT_DEFAULT].attr);
271: }
272:
273: static int lines_required_for_graphical(void)
274: {
275: item_t *it;
276:
277: if ((it = get_current_item()))
278: return get_ngraphs() * ((2 * c_graph_height) + 5);
279: else
280: return INT_MAX;
281: }
282:
283: static int lines_required_for_detailed(void)
284: {
285: if (get_current_item())
286: return 2 + ((get_current_item()->i_nattrs + 1) / 2);
287: else
288: return INT_MAX;
289: }
290:
291: static void __draw_graphic(stat_attr_hist_t *a, int selected, int xunit)
292: {
293: int w;
294: graph_t *g;
295: g = create_configued_graph(&a->a_hist, c_graph_height, a->a_unit, xunit);
296:
297: NEXT_ROW;
298: putl("RX %s [%s]",
299: g->g_rx.t_y_unit, type2desc(a->a_type));
300:
301: if (selected) {
302: move(row, 72);
303: attron(A_BOLD);
304: addstr("(sel)");
305: attroff(A_BOLD);
306: move(row, 0);
307: }
308:
309: for (w = (c_graph_height - 1); w >= 0; w--) {
310: NEXT_ROW;
311: putl(" %8.2f %s\n", g->g_rx.t_y_scale[w], (char *) g->g_rx.t_data + (w * (HISTORY_SIZE + 1)));
312: }
313:
314: move(row, 71);
315: putl("[%.2f%%]", rtiming.rt_variance.v_error);
316: NEXT_ROW;
317: putl(" 1 5 10 15 20 25 30 35 40 45 50 55 60 %s", g->g_rx.t_x_unit);
318:
319: NEXT_ROW;
320: putl("TX %s", g->g_tx.t_y_unit);
321:
322: for (w = (c_graph_height - 1); w >= 0; w--) {
323: NEXT_ROW;
324: putl(" %8.2f %s\n", g->g_tx.t_y_scale[w], (char *) g->g_tx.t_data + (w * (HISTORY_SIZE + 1)));
325: }
326:
327: move(row, 71);
328: putl("[%.2f%%]", rtiming.rt_variance.v_error);
329: NEXT_ROW;
330: putl(" 1 5 10 15 20 25 30 35 40 45 50 55 60 %s", g->g_tx.t_x_unit);
331:
332: free_graph(g);
333: }
334:
335: static void draw_graphic(void)
336: {
337: int i;
338:
339: for (i = 0; i < get_ngraphs(); i++) {
340: stat_attr_hist_t *a = (stat_attr_hist_t *) current_attr(i);
341:
342: if (!(a->a_flags & ATTR_FLAG_HISTORY))
343: continue;
344:
345: if (a)
346: __draw_graphic(a, get_current_item()->i_graph_sel == i,
347: get_current_item()->i_unit[i]);
348:
349: if (i < (get_ngraphs() - 1)) {
350: int n;
351: NEXT_ROW;
352: for (n = 1; n < cols-1; n += 2)
353: mvaddch(row, n, ACS_HLINE);
354: }
355: }
356:
357: }
358:
359: static void draw_attr_detail(stat_attr_t *attr, void *arg)
360: {
361: int rxprec, txprec;
362: double rx, tx;
363: char *rxu, *txu;
364: int *t = (int *) arg;
365:
366: rx = cancel_down(attr_get_rx(attr), attr->a_unit, &rxu, &rxprec);
367: tx = cancel_down(attr_get_tx(attr), attr->a_unit, &txu, &txprec);
368:
369: if (0 == *t) {
370: NEXT_ROW;
371: putl(" %-12s%9.*f%-3s %9.*f%-3s",
372: type2desc(attr->a_type),
373: rxprec, rx, rxu, txprec, tx, txu);
374:
375: if (!(attr->a_flags & ATTR_FLAG_RX_ENABLED)) {
376: move(row, 20);
377: addstr("N/A");
378: }
379:
380: if (!(attr->a_flags & ATTR_FLAG_TX_ENABLED)) {
381: move(row, 33);
382: addstr("N/A");
383: }
384:
385: move(row, 40);
386: *t = 1;
387: } else {
388: putl(" %-12s%9.*f%-3s %9.*f%-3s",
389: type2desc(attr->a_type),
390: rxprec, rx, rxu, txprec, tx, txu);
391:
392: if (!(attr->a_flags & ATTR_FLAG_RX_ENABLED)) {
393: move(row, 60);
394: addstr("N/A");
395: }
396:
397: if (!(attr->a_flags & ATTR_FLAG_TX_ENABLED)) {
398: move(row, 73);
399: addstr("N/A");
400: }
401:
402: move(row, 0);
403: *t = 0;
404: }
405: }
406:
407: static void draw_detailed(void)
408: {
409: int start_pos, end_pos, i;
410: item_t *intf;
411: int attr_flag = 0;
412:
413: intf = get_current_item();
414:
415: if (NULL == intf)
416: return;
417:
418: move(row, 39);
419: addch(ACS_TTEE);
420: move(row, 0);
421:
422: NEXT_ROW;
423: start_pos = row;
424: putl(" RX TX " \
425: " RX TX");
426:
427: foreach_attr(intf, draw_attr_detail, &attr_flag);
428:
429: end_pos = row;
430: for (i = start_pos; i <= end_pos; i++) {
431: move(i, 39);
432: addch(ACS_VLINE);
433: }
434: move(end_pos, 0);
435: }
436:
437: static void print_quit(void)
438: {
439: /*
440: * This could be done with ncurses windows but i'm way too lazy to
441: * look into it
442: */
443: int i, y = (rows/2) - 2;
444: char *text = " Really Quit? (y/n) ";
445: int len = strlen(text);
446: int x = (cols/2) - (len / 2);
447:
448: attrset(A_STANDOUT);
449: mvaddch(y - 2, x - 1, ACS_ULCORNER);
450: mvaddch(y + 2, x - 1, ACS_LLCORNER);
451: mvaddch(y - 2, x + len, ACS_URCORNER);
452: mvaddch(y + 2, x + len, ACS_LRCORNER);
453:
454: for (i = 0; i < 3; i++) {
455: mvaddch(y - 1 + i, x + len, ACS_VLINE);
456: mvaddch(y - 1 + i, x - 1 ,ACS_VLINE);
457: }
458:
459: for (i = 0; i < len; i++) {
460: mvaddch(y - 2, x + i, ACS_HLINE);
461: mvaddch(y - 1, x + i, ' ');
462: mvaddch(y + 1, x + i, ' ');
463: mvaddch(y + 2, x + i, ACS_HLINE);
464: }
465:
466: mvaddstr(y, x, text);
467: attroff(A_STANDOUT);
468: }
469:
470: static void draw_help(void)
471: {
472: #define HW 46
473: #define HH 19
474: int i, y = (rows/2) - (HH/2);
475: int x = (cols/2) - (HW/2);
476: char pad[HW+1];
477:
478: memset(pad, ' ', sizeof(pad));
479: pad[sizeof(pad) - 1] = '\0';
480:
481: attron(A_STANDOUT);
482:
483: for (i = 0; i < HH; i++)
484: mvaddnstr(y + i, x, pad, -1);
485:
486: mvaddch(y - 1, x - 1, ACS_ULCORNER);
487: mvaddch(y + HH, x - 1, ACS_LLCORNER);
488:
489: mvaddch(y - 1, x + HW, ACS_URCORNER);
490: mvaddch(y + HH, x + HW, ACS_LRCORNER);
491:
492: for (i = 0; i < HH; i++) {
493: mvaddch(y + i, x - 1, ACS_VLINE);
494: mvaddch(y + i, x + HW, ACS_VLINE);
495: }
496:
497: for (i = 0; i < HW; i++) {
498: mvaddch(y - 1, x + i, ACS_HLINE);
499: mvaddch(y + HH, x + i, ACS_HLINE);
500: }
501:
502: attron(A_BOLD);
503: mvaddnstr(y- 1, x+15, "QUICK REFERENCE", -1);
504: attron(A_UNDERLINE);
505: mvaddnstr(y+ 0, x+3, "Navigation", -1);
506: attroff(A_BOLD | A_UNDERLINE);
507: mvaddnstr(y+ 0, x+35, "[Page 1/2]", -1);
508:
509: mvaddnstr(y+ 1, x+5, "Up Previous interface", -1);
510: mvaddnstr(y+ 2, x+5, "Down Next interface", -1);
511: mvaddnstr(y+ 3, x+5, "Pg-Up Previous node", -1);
512: mvaddnstr(y+ 4, x+5, "Pg-Down Next node", -1);
513: mvaddnstr(y+ 5, x+5, "< Previous graph", -1);
514: mvaddnstr(y+ 6, x+5, "> Next graph", -1);
515: mvaddnstr(y+ 7, x+5, "0-9 Goto n-th interface", -1);
516: mvaddnstr(y+ 8, x+5, "? Toggle quick reference", -1);
517: mvaddnstr(y+ 9, x+5, "q Quit bmon", -1);
518:
519: attron(A_BOLD | A_UNDERLINE);
520: mvaddnstr(y+11, x+3, "Display Settings", -1);
521: attroff(A_BOLD | A_UNDERLINE);
522:
523: mvaddnstr(y+12, x+5, "g Toggle graphical statistics", -1);
524: mvaddnstr(y+13, x+5, "d Toggle detailed statistics", -1);
525: mvaddnstr(y+14, x+5, "c Toggle combined node list", -1);
526: mvaddnstr(y+15, x+5, "l Toggle interface list", -1);
527: mvaddnstr(y+16, x+5, "f (Un)fold sub interfaces", -1);
528:
529: attroff(A_STANDOUT);
530: }
531:
532: static void draw_help_2(void)
533: {
534: #define HW 46
535: #define HH 19
536: int i, y = (rows/2) - (HH/2);
537: int x = (cols/2) - (HW/2);
538: char pad[HW+1];
539:
540: memset(pad, ' ', sizeof(pad));
541: pad[sizeof(pad) - 1] = '\0';
542:
543: attron(A_STANDOUT);
544:
545: for (i = 0; i < HH; i++)
546: mvaddnstr(y + i, x, pad, -1);
547:
548: mvaddch(y - 1, x - 1, ACS_ULCORNER);
549: mvaddch(y + HH, x - 1, ACS_LLCORNER);
550:
551: mvaddch(y - 1, x + HW, ACS_URCORNER);
552: mvaddch(y + HH, x + HW, ACS_LRCORNER);
553:
554: for (i = 0; i < HH; i++) {
555: mvaddch(y + i, x - 1, ACS_VLINE);
556: mvaddch(y + i, x + HW, ACS_VLINE);
557: }
558:
559: for (i = 0; i < HW; i++) {
560: mvaddch(y - 1, x + i, ACS_HLINE);
561: mvaddch(y + HH, x + i, ACS_HLINE);
562: }
563:
564: attron(A_BOLD);
565: mvaddnstr(y- 1, x+15, "QUICK REFERENCE", -1);
566: attron(A_UNDERLINE);
567: mvaddnstr(y+ 0, x+3, "Graph Management", -1);
568: attroff(A_BOLD | A_UNDERLINE);
569: mvaddnstr(y+ 0, x+35, "[Page 2/2]", -1);
570:
571: mvaddnstr(y+ 1, x+5, "n New graph", -1);
572: mvaddnstr(y+ 2, x+5, "x Delete graph", -1);
573: mvaddnstr(y+ 3, x+5, "a Next attribute", -1);
574:
575: attron(A_BOLD | A_UNDERLINE);
576: mvaddnstr(y+ 5, x+3, "Measurement Units", -1);
577: attroff(A_BOLD | A_UNDERLINE);
578:
579: mvaddnstr(y+ 6, x+5, "R Read Interval", -1);
580: mvaddnstr(y+ 7, x+5, "S Seconds", -1);
581: mvaddnstr(y+ 8, x+5, "M Minutes", -1);
582: mvaddnstr(y+ 9, x+5, "H Hours", -1);
583: mvaddnstr(y+10, x+5, "D Days", -1);
584: attroff(A_STANDOUT);
585: }
586:
587: static void print_content(void)
588: {
589: int cnt = 0;
590: int required_lines = 0, disable_detailed = 0, disabled_graphical = 0;
591:
592: if (NULL == get_current_node())
593: return;
594:
595: if (c_list_in_list) {
596: NEXT_ROW;
597: attron(A_BOLD);
598: putl(" Name RX TX");
599: attron(A_BOLD);
600:
601: if (c_use_colors)
602: attrset(COLOR_PAIR(LAYOUT_HEADER) | layout[LAYOUT_HEADER].attr);
603:
604: NEXT_ROW;
605: hline(ACS_HLINE, cols);
606:
607: move(row, 28);
608: addch(ACS_TTEE);
609: move(row, 54);
610: addch(ACS_TTEE);
611: move(row, 0);
612:
613: if (c_combined_node_list)
614: foreach_node(draw_node, &cnt);
615: else
616: draw_node(get_current_node(), NULL);
617: } else {
618: NEXT_ROW;
619: hline(ACS_HLINE, cols);
620: move(row, 24);
621: addstr(" Press l to enable list view ");
622: move(row, 0);
623: }
624:
625: /*
626: * calculate lines required for graphical and detailed stats unfolded
627: */
628: if (c_graphical_in_list)
629: required_lines += lines_required_for_graphical();
630: else
631: required_lines++;
632:
633: if (c_detailed_in_list)
634: required_lines += lines_required_for_detailed();
635: else
636: required_lines++;
637:
638: if ((rows - row) <= (required_lines + 1)) {
639: /*
640: * not enough lines, start over with detailed stats disabled
641: */
642: required_lines = 0;
643: disable_detailed = 1;
644:
645: /*
646: * 1 line for folded detailed stats display
647: */
648: required_lines++;
649:
650: if (c_graphical_in_list)
651: required_lines += lines_required_for_graphical();
652: else
653: required_lines++;
654:
655: if ((rows - row) <= (required_lines + 1)) {
656: /*
657: * bad luck, not even enough space for graphical stats
658: * reserve 2 lines for displaying folded detailed and
659: * graphical stats
660: */
661: required_lines = 2;
662: disabled_graphical = 1;
663: }
664: }
665:
666: /*
667: * Clear out spare space
668: */
669: while (row < (rows - (required_lines + 2))) {
670: NEXT_ROW; putl("");
671: move(row, 28);
672: addch(ACS_VLINE);
673: move(row, 54);
674: addch(ACS_VLINE);
675: }
676:
677: NEXT_ROW;
678: hline(ACS_HLINE, cols);
679:
680: if (c_graphical_in_list) {
681: if (disabled_graphical) {
682: move(row, 15);
683: addstr(" Increase screen size to see graphical statistics ");
684: move(row, 0);
685: } else {
686: move(row, 28);
687: addch(ACS_BTEE);
688: move(row, 54);
689: addch(ACS_BTEE);
690: move(row, 0);
691: draw_graphic();
692: }
693: } else {
694: move(row, 20);
695: addstr(" Press g to enable graphical statistics ");
696: move(row, 0);
697: }
698:
699: NEXT_ROW;
700: hline(ACS_HLINE, cols);
701:
702: if (c_detailed_in_list) {
703: if (disable_detailed) {
704: move(row, 15);
705: addstr(" Increase screen size to see detailed statistics ");
706: move(row, 0);
707: } else
708: draw_detailed();
709: } else {
710: move(row, 20);
711: addstr(" Press d to enable detailed statistics ");
712: move(row, 0);
713: }
714: }
715:
716:
717:
718: static void curses_draw(void)
719: {
720: if (NULL == get_current_node()) {
721: first_node();
722: first_item();
723: }
724:
725: row = 0;
726: move(0,0);
727:
728: getmaxyx(stdscr, rows, cols);
729:
730: if (cols < 80) {
731: clear();
732: putl("Screen must be at least 80 columns wide");
733: refresh();
734: return;
735: }
736:
737: if (c_use_colors)
738: attrset(COLOR_PAIR(LAYOUT_STATUSBAR) | layout[LAYOUT_STATUSBAR].attr);
739: else
740: attrset(A_REVERSE);
741:
742: if (get_current_node() && get_current_item()) {
743: putl(" %s on %s",
744: get_current_item()->i_name, get_current_node()->n_name);
745: }
746:
747: move(row, COLS - strlen(PACKAGE_STRING) - 1);
748: putl("%s", PACKAGE_STRING);
749: move(row, 0);
750:
751: if (c_use_colors)
752: attrset(COLOR_PAIR(LAYOUT_DEFAULT) | layout[LAYOUT_DEFAULT].attr);
753: else
754: attroff(A_REVERSE);
755:
756: print_content();
757:
758: if (quit_mode)
759: print_quit();
760: else if (print_help) {
761: if (help_page == 0)
762: draw_help();
763: else
764: draw_help_2();
765: }
766:
767: for (; row < rows-2;) {
768: move(++row, 0);
769: putl("");
770: }
771:
772: row = rows-1;
773: move(row, 0);
774:
775: if (c_use_colors)
776: attrset(COLOR_PAIR(LAYOUT_STATUSBAR) | layout[LAYOUT_STATUSBAR].attr);
777: else
778: attrset(A_REVERSE);
779:
780: if (1) {
781: char s[27];
782: time_t t = time(0);
783: double d;
784: int h, m;
785:
786: asctime_r(localtime(&t), s);
787: s[strlen(s) - 1] = '\0';
788: d = difftime(time(0), start_time);
789:
790: if (d / 3600) {
791: h = (int) d / 3600;
792: m = (int) d % 3600;
793: m /= 60;
794: } else {
795: h = 0;
796: m = (int) d / 60;
797: }
798:
799: putl(" %s (%dh/%dm)", s, h, m);
800: move(row, COLS - strlen("Press ? for help") - 1);
801: putl("%s", "Press ? for help");
802: move(row, 0);
803: }
804:
805: attrset(0);
806: refresh();
807: }
808:
809: static void fold(void)
810: {
811: item_t *intf = get_current_item();
812: node_t *node = get_current_node();
813: int fix = 0;
814:
815: if (NULL == intf || NULL == node)
816: return;
817:
818: if (intf->i_flags & ITEM_FLAG_IS_CHILD)
819: fix = 1;
820:
821: while (intf->i_flags & ITEM_FLAG_IS_CHILD)
822: intf = get_item(node, intf->i_parent);
823:
824: if (intf->i_flags & ITEM_FLAG_FOLDED)
825: intf->i_flags &= ~ITEM_FLAG_FOLDED;
826: else
827: intf->i_flags |= ITEM_FLAG_FOLDED;
828:
829: if (fix)
830: prev_item();
831: }
832:
833: static int handle_input(int ch)
834: {
835: switch (ch)
836: {
837: case 'q':
838: quit_mode = quit_mode ? 0 : 1;
839: return 1;
840:
841: case 0x1b:
842: quit_mode = 0;
843: print_help = 0;
844: return 1;
845:
846: case 'y':
847: if (quit_mode)
848: exit(0);
849: break;
850:
851: case 'a':
852: next_attr();
853: return 1;
854:
855: case 'n':
856: if (quit_mode)
857: quit_mode = 0;
858: else
859: new_graph();
860: return 1;
861:
862: case 'x':
863: del_graph();
864: return 1;
865:
866: case 'f':
867: fold();
868: return 1;
869:
870: case 12:
871: case KEY_CLEAR:
872: #ifdef HAVE_REDRAWWIN
873: redrawwin(stdscr);
874: #endif
875: clear();
876: return 1;
877:
878: case 'c':
879: c_combined_node_list = c_combined_node_list ? 0 : 1;
880: return 1;
881:
882: case 'S':
883: clear();
884: set_graph_unit(X_SEC);
885: return 1;
886:
887: case 'M':
888: clear();
889: set_graph_unit(X_MIN);
890: return 1;
891:
892: case 'H':
893: clear();
894: set_graph_unit(X_HOUR);
895: return 1;
896:
897: case 'D':
898: clear();
899: set_graph_unit(X_DAY);
900: return 1;
901:
902: case 'R':
903: clear();
904: set_graph_unit(X_READ);
905: return 1;
906:
907: case '?':
908: clear();
909: print_help = print_help ? 0 : 1;
910: return 1;
911:
912: case 'g':
913: c_graphical_in_list = c_graphical_in_list ? 0 : 1;
914: return 1;
915:
916: case 'd':
917: c_detailed_in_list = c_detailed_in_list ? 0 : 1;
918: return 1;
919:
920: case 'l':
921: c_list_in_list = c_list_in_list ? 0 : 1;
922: return 1;
923:
924: case KEY_PPAGE:
925: if (print_help)
926: help_page = help_page ? 0 : 1;
927: else
928: prev_node();
929: return 1;
930:
931: case KEY_NPAGE:
932: if (print_help)
933: help_page = help_page ? 0 : 1;
934: else
935: next_node();
936: return 1;
937:
938: case KEY_DOWN:
939: if (next_item() == END_OF_LIST) {
940: if (next_node() != END_OF_LIST)
941: first_item();
942: }
943: return 1;
944:
945: case KEY_UP:
946: if (prev_item() == END_OF_LIST) {
947: if (prev_node() != END_OF_LIST)
948: last_item();
949: }
950: return 1;
951:
952: case '0':
953: case '1':
954: case '2':
955: case '3':
956: case '4':
957: case '5':
958: case '6':
959: case '7':
960: case '8':
961: case '9':
962: goto_item(ch - 48);
963: return 1;
964:
965: case '>':
966: next_graph();
967: return 1;
968:
969: case '<':
970: prev_graph();
971: return 1;
972:
973: default:
974: if (get_current_item())
975: if (handle_bindings(ch, get_current_item()->i_name))
976: return 1;
977: break;
978: }
979:
980: return 0;
981: }
982:
983: static void curses_pre(void)
984: {
985: for (;;) {
986: int ch = getch();
987:
988: if (ch == -1)
989: break;
990:
991: if (handle_input(ch))
992: curses_draw();
993: }
994: }
995:
996: static int curses_probe(void)
997: {
998: /* XXX? */
999: return 1;
1000: }
1001:
1002: static void print_module_help(void)
1003: {
1004: printf(
1005: "curses - Curses Output\n" \
1006: "\n" \
1007: " Interactive curses UI. Type '?' to get some help.\n" \
1008: " Author: Thomas Graf <tgraf@suug.ch>\n" \
1009: "\n" \
1010: " Options:\n" \
1011: " fgchar=CHAR Foreground character (default: '*')\n" \
1012: " bgchar=CHAR Background character (default: '.')\n" \
1013: " nchar=CHAR Noise character (default: ':')\n" \
1014: " uchar=CHAR Unknown character (default: '?')\n" \
1015: " height=NUM Height of graph (default: 6)\n" \
1016: " xunit=UNIT X-Axis Unit (default: seconds)\n" \
1017: " yunit=UNIT Y-Axis Unit (default: dynamic)\n" \
1018: " nocolors Do not use colors\n" \
1019: " nototal Do not print per node total\n" \
1020: " nosource Do not print the source of a item\n" \
1021: " cnl Combined node list\n" \
1022: " graph Show graphical stats by default\n" \
1023: " detail Show detailed stats by default\n");
1024: }
1025:
1026: static void curses_set_opts(tv_t *attrs)
1027: {
1028: while (attrs) {
1029: if (!strcasecmp(attrs->type, "fgchar") && attrs->value)
1030: set_fg_char(attrs->value[0]);
1031: else if (!strcasecmp(attrs->type, "bgchar") && attrs->value)
1032: set_bg_char(attrs->value[0]);
1033: else if (!strcasecmp(attrs->type, "nchar") && attrs->value)
1034: set_noise_char(attrs->value[0]);
1035: else if (!strcasecmp(attrs->type, "uchar") && attrs->value)
1036: set_unk_char(attrs->value[0]);
1037: else if (!strcasecmp(attrs->type, "xunit") && attrs->value)
1038: set_x_unit(attrs->value, 1);
1039: else if (!strcasecmp(attrs->type, "yunit") && attrs->value)
1040: set_y_unit(attrs->value);
1041: else if (!strcasecmp(attrs->type, "height") && attrs->value)
1042: c_graph_height = strtol(attrs->value, NULL, 0);
1043: else if (!strcasecmp(attrs->type, "cnl"))
1044: c_combined_node_list = 1;
1045: else if (!strcasecmp(attrs->type, "graph"))
1046: c_graphical_in_list = 1;
1047: else if (!strcasecmp(attrs->type, "detail"))
1048: c_detailed_in_list = 1;
1049: else if (!strcasecmp(attrs->type, "nocolors"))
1050: c_use_colors = 0;
1051: else if (!strcasecmp(attrs->type, "nototal"))
1052: c_nototal = 1;
1053: else if (!strcasecmp(attrs->type, "nosource"))
1054: c_nosource = 1;
1055: else if (!strcasecmp(attrs->type, "help")) {
1056: print_module_help();
1057: exit(0);
1058: }
1059:
1060: attrs = attrs->next;
1061: }
1062: }
1063:
1064: static struct output_module curses_ops = {
1065: .om_name = "curses",
1066: .om_init = curses_init,
1067: .om_shutdown = curses_shutdown,
1068: .om_pre = curses_pre,
1069: .om_draw = curses_draw,
1070: .om_set_opts = curses_set_opts,
1071: .om_probe = curses_probe,
1072: };
1073:
1074: static void __init do_curses_init(void)
1075: {
1076: register_output_module(&curses_ops);
1077: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>