xref: /dflybsd-src/usr.bin/dsynth/ncurses.c (revision 2295606ee0a1e6ce0e7a6a23146a9551e936b459)
1ea37671dSMatthew Dillon /*
2ea37671dSMatthew Dillon  * Copyright (c) 2019 The DragonFly Project.  All rights reserved.
3ea37671dSMatthew Dillon  *
4ea37671dSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5ea37671dSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6ea37671dSMatthew Dillon  *
7ea37671dSMatthew Dillon  * This code uses concepts and configuration based on 'synth', by
8ea37671dSMatthew Dillon  * John R. Marino <draco@marino.st>, which was written in ada.
9ea37671dSMatthew Dillon  *
10ea37671dSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
11ea37671dSMatthew Dillon  * modification, are permitted provided that the following conditions
12ea37671dSMatthew Dillon  * are met:
13ea37671dSMatthew Dillon  *
14ea37671dSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
15ea37671dSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
16ea37671dSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
17ea37671dSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
18ea37671dSMatthew Dillon  *    the documentation and/or other materials provided with the
19ea37671dSMatthew Dillon  *    distribution.
20ea37671dSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
21ea37671dSMatthew Dillon  *    contributors may be used to endorse or promote products derived
22ea37671dSMatthew Dillon  *    from this software without specific, prior written permission.
23ea37671dSMatthew Dillon  *
24ea37671dSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25ea37671dSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26ea37671dSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27ea37671dSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
28ea37671dSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29ea37671dSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30ea37671dSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31ea37671dSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32ea37671dSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33ea37671dSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34ea37671dSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35ea37671dSMatthew Dillon  * SUCH DAMAGE.
36ea37671dSMatthew Dillon  */
37ea37671dSMatthew Dillon #include "dsynth.h"
38ea37671dSMatthew Dillon 
39ea37671dSMatthew Dillon #include <curses.h>
40ea37671dSMatthew Dillon 
41ea37671dSMatthew Dillon /*
42ea37671dSMatthew Dillon  * ncurses - LINES, COLS are the main things we care about
43ea37671dSMatthew Dillon  */
44ea37671dSMatthew Dillon static WINDOW *CWin;
45ea37671dSMatthew Dillon static WINDOW *CMon;
46ea37671dSMatthew Dillon static const char *Line0 = " Total -       Built -      Ignored -      "
47ea37671dSMatthew Dillon 			   "Load -      Pkg/hour -               ";
48ea37671dSMatthew Dillon static const char *Line1 = "  Left -      Failed -      Skipped -      "
49ea37671dSMatthew Dillon 			   "Swap -       Impulse -      --:--:-- ";
50ea37671dSMatthew Dillon static const char *LineB = "==========================================="
51ea37671dSMatthew Dillon 			   "====================================";
52ea37671dSMatthew Dillon static const char *LineI = " ID  Duration  Build Phase      Origin     "
53ea37671dSMatthew Dillon 			   "                               Lines";
54ea37671dSMatthew Dillon 
55ea37671dSMatthew Dillon static int LastReduce;
56aac7a6d9SMatthew Dillon static monitorlog_t nclog;
57ea37671dSMatthew Dillon 
58ea37671dSMatthew Dillon #define TOTAL_COL	7
59ea37671dSMatthew Dillon #define BUILT_COL	21
60ea37671dSMatthew Dillon #define IGNORED_COL	36
61ea37671dSMatthew Dillon #define LOAD_COL	48
62ea37671dSMatthew Dillon #define GPKGRATE_COL	64
63ea37671dSMatthew Dillon #define REDUCE_COL	71
64ea37671dSMatthew Dillon 
65ea37671dSMatthew Dillon #define LEFT_COL	7
66ea37671dSMatthew Dillon #define FAILED_COL	21
67ea37671dSMatthew Dillon #define SKIPPED_COL	36
68ea37671dSMatthew Dillon #define SWAP_COL	48
69ea37671dSMatthew Dillon #define IMPULSE_COL	64
70ea37671dSMatthew Dillon #define TIME_COL	71
71ea37671dSMatthew Dillon 
72ea37671dSMatthew Dillon #define ID_COL		1
73ea37671dSMatthew Dillon #define DURATION_COL	5
74ea37671dSMatthew Dillon #define BUILD_PHASE_COL	15
75ea37671dSMatthew Dillon #define ORIGIN_COL	32
76d7cc0214SMatthew Dillon #define LINES_COL	72
77ea37671dSMatthew Dillon 
78ea37671dSMatthew Dillon /*
79ea37671dSMatthew Dillon  * The row that the worker list starts on, and the row that the log starts
80ea37671dSMatthew Dillon  * on.
81ea37671dSMatthew Dillon  */
82ea37671dSMatthew Dillon #define WORKER_START	5
83ea37671dSMatthew Dillon #define LOG_START	(WORKER_START + MaxWorkers + 1)
84ea37671dSMatthew Dillon 
85ea37671dSMatthew Dillon static void NCursesReset(void);
86ea37671dSMatthew Dillon 
87ea37671dSMatthew Dillon static void
NCursesInit(void)88ea37671dSMatthew Dillon NCursesInit(void)
89ea37671dSMatthew Dillon {
90ea37671dSMatthew Dillon 	if (UseNCurses == 0)
91ea37671dSMatthew Dillon 		return;
92ea37671dSMatthew Dillon 
93ea37671dSMatthew Dillon 	CWin = initscr();
94ea37671dSMatthew Dillon 	NCursesReset();
95ea37671dSMatthew Dillon 
96ea37671dSMatthew Dillon 	intrflush(stdscr, FALSE);
97ea37671dSMatthew Dillon 	nonl();
98ea37671dSMatthew Dillon 	noecho();
99ea37671dSMatthew Dillon 	cbreak();
100ea37671dSMatthew Dillon 
101ea37671dSMatthew Dillon 	start_color();
102ea37671dSMatthew Dillon 	use_default_colors();
103ea37671dSMatthew Dillon 	init_pair(1, COLOR_RED, -1);
104ea37671dSMatthew Dillon 	init_pair(2, COLOR_GREEN, -1);
105ea37671dSMatthew Dillon 	init_pair(3, -1, -1);
106ea37671dSMatthew Dillon }
107ea37671dSMatthew Dillon 
108ea37671dSMatthew Dillon static void
NCursesReset(void)109ea37671dSMatthew Dillon NCursesReset(void)
110ea37671dSMatthew Dillon {
111ea37671dSMatthew Dillon 	int i;
112ea37671dSMatthew Dillon 
113ea37671dSMatthew Dillon 	if (UseNCurses == 0)
114ea37671dSMatthew Dillon 		return;
115ea37671dSMatthew Dillon 
116ea37671dSMatthew Dillon 	if (CMon) {
117ea37671dSMatthew Dillon 		delwin(CMon);
118ea37671dSMatthew Dillon 		CMon = NULL;
119ea37671dSMatthew Dillon 	}
120ea37671dSMatthew Dillon 
121ea37671dSMatthew Dillon 	werase(CWin);
122ea37671dSMatthew Dillon 	curs_set(0);
123ea37671dSMatthew Dillon 	redrawwin(CWin);
124ea37671dSMatthew Dillon 	wrefresh(CWin);
125ea37671dSMatthew Dillon 	mvwprintw(CWin, 0, 0, "%s", Line0);
126ea37671dSMatthew Dillon 	mvwprintw(CWin, 1, 0, "%s", Line1);
127ea37671dSMatthew Dillon 	mvwprintw(CWin, 2, 0, "%s", LineB);
128ea37671dSMatthew Dillon 	mvwprintw(CWin, 3, 0, "%s", LineI);
129ea37671dSMatthew Dillon 	mvwprintw(CWin, 4, 0, "%s", LineB);
130ea37671dSMatthew Dillon 
131ea37671dSMatthew Dillon 	for (i = 0; i < MaxWorkers; ++i) {
132ea37671dSMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, ID_COL, "%02d", i);
133ea37671dSMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, DURATION_COL, "--:--:--");
134ea37671dSMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, BUILD_PHASE_COL, "Idle");
135d7cc0214SMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, ORIGIN_COL, "%38.38s", "");
136d7cc0214SMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, LINES_COL, "%7.7s", "");
137ea37671dSMatthew Dillon 	}
138ea37671dSMatthew Dillon 	mvwprintw(CWin, WORKER_START + MaxWorkers, 0, "%s", LineB);
139ea37671dSMatthew Dillon 	wrefresh(CWin);
140ea37671dSMatthew Dillon 
141ea37671dSMatthew Dillon 	CMon = subwin(CWin, 0, 0, LOG_START, 0);
142ea37671dSMatthew Dillon 	scrollok(CMon, 1);
143aac7a6d9SMatthew Dillon 
144aac7a6d9SMatthew Dillon 	bzero(&nclog, sizeof(nclog));
145aac7a6d9SMatthew Dillon 	nclog.fd = dlog00_fd();
146ea37671dSMatthew Dillon 	nodelay(CMon, 1);
147ea37671dSMatthew Dillon 
148ea37671dSMatthew Dillon 	LastReduce = -1;
149ea37671dSMatthew Dillon }
150ea37671dSMatthew Dillon 
151ea37671dSMatthew Dillon static void
NCursesUpdateTop(topinfo_t * info)152ea37671dSMatthew Dillon NCursesUpdateTop(topinfo_t *info)
153ea37671dSMatthew Dillon {
154ea37671dSMatthew Dillon 	if (UseNCurses == 0)
155ea37671dSMatthew Dillon 		return;
156ea37671dSMatthew Dillon 
157*2295606eSMatthew Dillon 	mvwprintw(CWin, 0, TOTAL_COL, "%-6d", info->total);
158*2295606eSMatthew Dillon 	mvwprintw(CWin, 0, BUILT_COL, "%-6d", info->successful);
159*2295606eSMatthew Dillon 	mvwprintw(CWin, 0, IGNORED_COL, "%-6d", info->ignored);
160ea37671dSMatthew Dillon 	if (info->dload[0] > 999.9)
161ea37671dSMatthew Dillon 		mvwprintw(CWin, 0, LOAD_COL, "%5.0f", info->dload[0]);
162ea37671dSMatthew Dillon 	else
163ea37671dSMatthew Dillon 		mvwprintw(CWin, 0, LOAD_COL, "%5.1f", info->dload[0]);
164*2295606eSMatthew Dillon 	mvwprintw(CWin, 0, GPKGRATE_COL, "%-6d", info->pkgrate);
165ea37671dSMatthew Dillon 
166ea37671dSMatthew Dillon 	/*
167ea37671dSMatthew Dillon 	 * If dynamic worker reduction is active include a field,
168ea37671dSMatthew Dillon 	 * Otherwise blank the field.
169ea37671dSMatthew Dillon 	 */
170aac7a6d9SMatthew Dillon 	if (LastReduce != info->dynmaxworkers) {
171aac7a6d9SMatthew Dillon 		LastReduce = info->dynmaxworkers;
172ea37671dSMatthew Dillon 		if (MaxWorkers == LastReduce)
173ea37671dSMatthew Dillon 			mvwprintw(CWin, 0, REDUCE_COL, "       ");
174ea37671dSMatthew Dillon 		else
1754986398eSMatthew Dillon 			mvwprintw(CWin, 0, REDUCE_COL, "Lim %-3d",
176ea37671dSMatthew Dillon 				  LastReduce);
177ea37671dSMatthew Dillon 	}
178ea37671dSMatthew Dillon 
179*2295606eSMatthew Dillon 	mvwprintw(CWin, 1, LEFT_COL, "%-6d", info->remaining);
180*2295606eSMatthew Dillon 	mvwprintw(CWin, 1, FAILED_COL, "%-6d", info->failed);
181*2295606eSMatthew Dillon 	mvwprintw(CWin, 1, SKIPPED_COL, "%-6d", info->skipped);
182ea37671dSMatthew Dillon 	if (info->noswap)
183ea37671dSMatthew Dillon 		mvwprintw(CWin, 1, SWAP_COL, "-   ");
184ea37671dSMatthew Dillon 	else
185ea37671dSMatthew Dillon 		mvwprintw(CWin, 1, SWAP_COL, "%5.1f", info->dswap);
186*2295606eSMatthew Dillon 	mvwprintw(CWin, 1, IMPULSE_COL, "%-6d", info->pkgimpulse);
187ea37671dSMatthew Dillon 	if (info->h > 99)
188ea37671dSMatthew Dillon 		mvwprintw(CWin, 1, TIME_COL-1, "%3d:%02d:%02d",
189ea37671dSMatthew Dillon 			  info->h, info->m, info->s);
190ea37671dSMatthew Dillon 	else
191ea37671dSMatthew Dillon 		mvwprintw(CWin, 1, TIME_COL, "%02d:%02d:%02d",
192ea37671dSMatthew Dillon 			  info->h, info->m, info->s);
193ea37671dSMatthew Dillon }
194ea37671dSMatthew Dillon 
195ea37671dSMatthew Dillon static void
NCursesUpdateLogs(void)196ea37671dSMatthew Dillon NCursesUpdateLogs(void)
197ea37671dSMatthew Dillon {
198ea37671dSMatthew Dillon 	char *ptr;
199ea37671dSMatthew Dillon 	char c;
200ea37671dSMatthew Dillon 	ssize_t n;
201ea37671dSMatthew Dillon 	int w;
202ea37671dSMatthew Dillon 
203ea37671dSMatthew Dillon 	if (UseNCurses == 0)
204ea37671dSMatthew Dillon 		return;
205ea37671dSMatthew Dillon 
206ea37671dSMatthew Dillon 	for (;;) {
207aac7a6d9SMatthew Dillon 		n = readlogline(&nclog, &ptr);
208ea37671dSMatthew Dillon 		if (n < 0)
209ea37671dSMatthew Dillon 			break;
210ea37671dSMatthew Dillon 		if (n == 0)
211ea37671dSMatthew Dillon 			continue;
212ea37671dSMatthew Dillon 
213ea37671dSMatthew Dillon 		/*
214ea37671dSMatthew Dillon 		 * Scroll down
215ea37671dSMatthew Dillon 		 */
216ea37671dSMatthew Dillon 		if (n > COLS)
217ea37671dSMatthew Dillon 			w = COLS;
218ea37671dSMatthew Dillon 		else
219ea37671dSMatthew Dillon 			w = n;
220ea37671dSMatthew Dillon 		c = ptr[w];
221ea37671dSMatthew Dillon 		ptr[w] = 0;
222ea37671dSMatthew Dillon 
223ea37671dSMatthew Dillon 		/*
224ea37671dSMatthew Dillon 		 * Filter out these logs from the display (they remain in
225ea37671dSMatthew Dillon 		 * the 00*.log file) to reduce clutter.
226ea37671dSMatthew Dillon 		 */
227aac7a6d9SMatthew Dillon 		if (strncmp(ptr, "[XXX] Load=", 11) != 0) {
228ea37671dSMatthew Dillon 			/*
229ea37671dSMatthew Dillon 			 * Output possibly colored log line
230ea37671dSMatthew Dillon 			 */
231ea37671dSMatthew Dillon 			wscrl(CMon, -1);
232ea37671dSMatthew Dillon 			if (strstr(ptr, "] SUCCESS ")) {
233ea37671dSMatthew Dillon 				wattrset(CMon, COLOR_PAIR(2));
234ea37671dSMatthew Dillon 			} else if (strstr(ptr, "] FAILURE ")) {
235ea37671dSMatthew Dillon 				wattrset(CMon, COLOR_PAIR(1));
236ea37671dSMatthew Dillon 			}
237ea37671dSMatthew Dillon 			mvwprintw(CMon, 0, 0, "%s", ptr);
238ea37671dSMatthew Dillon 			wattrset(CMon, COLOR_PAIR(3));
239ea37671dSMatthew Dillon 		}
240aac7a6d9SMatthew Dillon 		ptr[w] = c;
241aac7a6d9SMatthew Dillon 	}
242ea37671dSMatthew Dillon }
243ea37671dSMatthew Dillon 
244ea37671dSMatthew Dillon static void
NCursesUpdate(worker_t * work,const char * portdir)245aac7a6d9SMatthew Dillon NCursesUpdate(worker_t *work, const char *portdir)
246ea37671dSMatthew Dillon {
247ea37671dSMatthew Dillon 	const char *phase;
248ea37671dSMatthew Dillon 	const char *origin;
249ea37671dSMatthew Dillon 	time_t t;
250ea37671dSMatthew Dillon 	int i = work->index;
251ea37671dSMatthew Dillon 	int h;
252ea37671dSMatthew Dillon 	int m;
253ea37671dSMatthew Dillon 	int s;
254ea37671dSMatthew Dillon 
255ea37671dSMatthew Dillon 	if (UseNCurses == 0)
256ea37671dSMatthew Dillon 		return;
257ea37671dSMatthew Dillon 
258ea37671dSMatthew Dillon 	phase = "Unknown";
259ea37671dSMatthew Dillon 	origin = "";
260ea37671dSMatthew Dillon 
261ea37671dSMatthew Dillon 	switch(work->state) {
262ea37671dSMatthew Dillon 	case WORKER_NONE:
263ea37671dSMatthew Dillon 		phase = "None";
264ea37671dSMatthew Dillon 		/* fall through */
265ea37671dSMatthew Dillon 	case WORKER_IDLE:
266ea37671dSMatthew Dillon 		if (work->state == WORKER_IDLE)
267ea37671dSMatthew Dillon 			phase = "Idle";
268ea37671dSMatthew Dillon 		/* fall through */
269ea37671dSMatthew Dillon 	case WORKER_FAILED:
270ea37671dSMatthew Dillon 		if (work->state == WORKER_FAILED)
271ea37671dSMatthew Dillon 			phase = "Failed";
272ea37671dSMatthew Dillon 		/* fall through */
273ea37671dSMatthew Dillon 	case WORKER_EXITING:
274ea37671dSMatthew Dillon 		if (work->state == WORKER_EXITING)
275ea37671dSMatthew Dillon 			phase = "Exiting";
276ea37671dSMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, DURATION_COL,
277ea37671dSMatthew Dillon 			  "--:--:--");
278ea37671dSMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, BUILD_PHASE_COL,
279ea37671dSMatthew Dillon 			  "%-16.16s", phase);
280ea37671dSMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, ORIGIN_COL,
281d7cc0214SMatthew Dillon 			  "%-38.38s", "");
282ea37671dSMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, LINES_COL,
283d7cc0214SMatthew Dillon 			  "%-7.7s", "");
284ea37671dSMatthew Dillon 		return;
285ea37671dSMatthew Dillon 	case WORKER_PENDING:
286ea37671dSMatthew Dillon 		phase = "Pending";
287ea37671dSMatthew Dillon 		break;
288ea37671dSMatthew Dillon 	case WORKER_RUNNING:
289ea37671dSMatthew Dillon 		phase = "Running";
290ea37671dSMatthew Dillon 		break;
291ea37671dSMatthew Dillon 	case WORKER_DONE:
292ea37671dSMatthew Dillon 		phase = "Done";
293ea37671dSMatthew Dillon 		break;
294ea37671dSMatthew Dillon 	case WORKER_FROZEN:
295ea37671dSMatthew Dillon 		phase = "FROZEN";
296ea37671dSMatthew Dillon 		break;
297ea37671dSMatthew Dillon 	default:
298ea37671dSMatthew Dillon 		break;
299ea37671dSMatthew Dillon 	}
300ea37671dSMatthew Dillon 
301ea37671dSMatthew Dillon 	t = time(NULL) - work->start_time;
302ea37671dSMatthew Dillon 	s = t % 60;
303ea37671dSMatthew Dillon 	m = t / 60 % 60;
304ea37671dSMatthew Dillon 	h = t / 60 / 60;
305ea37671dSMatthew Dillon 
306ea37671dSMatthew Dillon 	if (work->state == WORKER_RUNNING)
307ea37671dSMatthew Dillon 		phase = getphasestr(work->phase);
308ea37671dSMatthew Dillon 
309aac7a6d9SMatthew Dillon 	/*
310aac7a6d9SMatthew Dillon 	 * When called from the monitor frontend portdir has to be passed
311aac7a6d9SMatthew Dillon 	 * in directly because work->pkg is not mapped.
312aac7a6d9SMatthew Dillon 	 */
313aac7a6d9SMatthew Dillon 	if (portdir)
314aac7a6d9SMatthew Dillon 		origin = portdir;
315aac7a6d9SMatthew Dillon 	else if (work->pkg)
316ea37671dSMatthew Dillon 		origin = work->pkg->portdir;
317ea37671dSMatthew Dillon 	else
318ea37671dSMatthew Dillon 		origin = "";
319ea37671dSMatthew Dillon 
320ea37671dSMatthew Dillon 	mvwprintw(CWin, WORKER_START + i, DURATION_COL,
321ea37671dSMatthew Dillon 		  "%02d:%02d:%02d", h, m, s);
322ea37671dSMatthew Dillon 	mvwprintw(CWin, WORKER_START + i, BUILD_PHASE_COL,
323ea37671dSMatthew Dillon 		  "%-16.16s", phase);
324ea37671dSMatthew Dillon 	mvwprintw(CWin, WORKER_START + i, ORIGIN_COL,
325d7cc0214SMatthew Dillon 		  "%-38.38s", origin);
326d7cc0214SMatthew Dillon 	if (work->lines > 9999999) {
327ea37671dSMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, LINES_COL,
328d7cc0214SMatthew Dillon 			  "%7s", "*MANY*%d", work->lines % 10);
329d7cc0214SMatthew Dillon 	} else {
330d7cc0214SMatthew Dillon 		mvwprintw(CWin, WORKER_START + i, LINES_COL,
331d7cc0214SMatthew Dillon 			  "%7d", work->lines);
332d7cc0214SMatthew Dillon 	}
333ea37671dSMatthew Dillon }
334ea37671dSMatthew Dillon 
335ea37671dSMatthew Dillon static void
NCursesSync(void)336ea37671dSMatthew Dillon NCursesSync(void)
337ea37671dSMatthew Dillon {
338ea37671dSMatthew Dillon 	int c;
339ea37671dSMatthew Dillon 
340ea37671dSMatthew Dillon 	if (UseNCurses == 0)
341ea37671dSMatthew Dillon 		return;
342ea37671dSMatthew Dillon 
343ea37671dSMatthew Dillon 	while ((c = wgetch(CMon)) != ERR) {
344ea37671dSMatthew Dillon 		if (c == KEY_RESIZE)
345ea37671dSMatthew Dillon 			NCursesReset();
346ea37671dSMatthew Dillon 	}
347ea37671dSMatthew Dillon 	wrefresh(CWin);
348ea37671dSMatthew Dillon 	wrefresh(CMon);
349ea37671dSMatthew Dillon }
350ea37671dSMatthew Dillon 
351ea37671dSMatthew Dillon static void
NCursesDone(void)352ea37671dSMatthew Dillon NCursesDone(void)
353ea37671dSMatthew Dillon {
354ea37671dSMatthew Dillon 	if (UseNCurses == 0)
355ea37671dSMatthew Dillon 		return;
356ea37671dSMatthew Dillon 
357ea37671dSMatthew Dillon 	endwin();
358ea37671dSMatthew Dillon }
359ea37671dSMatthew Dillon 
360ea37671dSMatthew Dillon runstats_t NCursesRunStats = {
361ea37671dSMatthew Dillon 	.init = NCursesInit,
362ea37671dSMatthew Dillon 	.done = NCursesDone,
363ea37671dSMatthew Dillon 	.reset = NCursesReset,
364ea37671dSMatthew Dillon 	.update = NCursesUpdate,
365ea37671dSMatthew Dillon 	.updateTop = NCursesUpdateTop,
366ea37671dSMatthew Dillon 	.updateLogs = NCursesUpdateLogs,
367ea37671dSMatthew Dillon 	.sync = NCursesSync
368ea37671dSMatthew Dillon };
369