Build separately from mLib.
[sw-tools] / src / pres_curses.c
CommitLineData
3315e8b3 1/* -*-c-*-
2 *
c2f4ecb4 3 * $Id: pres_curses.c,v 1.6 1999/07/27 14:04:19 mdw Exp $
3315e8b3 4 *
5 * Curses-based output presentation
6 *
7 * (c) 1999 EBI
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of sw-tools.
13 *
14 * sw-tools is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * sw-tools is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with sw-tools; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29/*----- Revision history --------------------------------------------------*
30 *
31 * $Log: pres_curses.c,v $
c2f4ecb4 32 * Revision 1.6 1999/07/27 14:04:19 mdw
33 * (Bug fix) Include the SIGWINCH handler even if `wresize' isn't known.
34 *
35 * Revision 1.5 1999/07/27 12:49:16 mdw
37aa0f71 36 * Slight tidying of resizing terminal handling.
37 *
38 * Revision 1.4 1999/07/16 16:52:28 mdw
4840d4f1 39 * `wbkdset' doesn't work so well. Use `wbkgd' instead.
40 *
5636c0ce 41 * Revision 1.3 1999/07/16 12:49:58 mdw
42 * Improve exit status display. New interface from `doto' project.
43 *
63124806 44 * Revision 1.2 1999/06/24 15:51:16 mdw
45 * Fix signal handlers so they don't corrupt `errno'.
46 *
47 * Revision 1.1.1.1 1999/06/02 16:53:35 mdw
48 * Initial import.
3315e8b3 49 *
50 */
51
52/*----- Header files ------------------------------------------------------*/
53
54#include "config.h"
55#ifdef HAVE_CURSES
56
57#include <errno.h>
58#include <signal.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62
63#include <sys/types.h>
64#include <unistd.h>
65
66#if defined(HAVE_NCURSES_H)
67# include <ncurses.h>
68#elif defined(HAVE_NCURSES_NCURSES_H)
69# include <ncurses/ncurses.h>
70#elif defined(HAVE_CURSES_H)
71# include <curses.h>
72#else
73# error "Where's your <curses.h> header?"
74#endif
75#include <term.h>
76
77#include <mLib/alloc.h>
78#include <mLib/report.h>
79
80#include "sw.h"
81#include "sw_arch.h"
82#include "pres_curses.h"
83
84#ifndef SIGWINCH
85# undef HAVE_WRESIZE
86#endif
87
88/*----- Data structures ---------------------------------------------------*/
89
90typedef struct cwin {
91 struct cwin *next;
92 WINDOW *w;
93 int top;
94 int height;
95 WINDOW *s;
96 archent *e;
97} cwin;
98
99/*----- Static variables --------------------------------------------------*/
100
101static cwin *cwins = 0;
102static int nwins = 0;
103
104/*----- Main code ---------------------------------------------------------*/
105
106/* --- @sizes@ --- *
107 *
108 * Arguments: ---
109 *
110 * Returns: ---
111 *
112 * Use: Calculates window sizes for all the windows. The heights are
113 * determined in a way which doesn't allow rounding errors to be
114 * an issue (although there will be up to a line's height
115 * difference between two windows). No actual changing of
116 * curses structures is done.
117 */
118
119static void sizes(void)
120{
121 cwin *c;
122 int t = 0, h = LINES, w = nwins;
123
124 for (c = cwins; c; c = c->next) {
125 int a = h / w;
126 c->top = t;
127 c->height = a - 1;
128 t += a;
129 h -= a;
130 w--;
131 }
132}
133
134/* --- @sig_tstp@ --- */
135
136#ifdef SIGTSTP
137static void sig_tstp(int s)
138{
63124806 139 int e = errno;
3315e8b3 140 endwin();
63124806 141 errno = e;
3315e8b3 142 raise(SIGSTOP);
143}
144#endif
145
146/* --- @sig_cont@ --- */
147
148#ifdef SIGTSTP
149static void sig_cont(int s)
150{
63124806 151 int e = errno;
3315e8b3 152 wrefresh(curscr);
63124806 153 errno = e;
3315e8b3 154}
155#endif
156
157/* --- @sig_winch@ --- */
158
37aa0f71 159#ifdef SIGWINCH
3315e8b3 160
161static void sig_winch(int s)
162{
63124806 163 int e = errno;
164
37aa0f71 165#ifdef HAVE_WRESIZE
166 cwin *c;
167
3315e8b3 168 endwin();
37aa0f71 169 wrefresh(curscr);
3315e8b3 170 sizes();
171 for (c = cwins; c; c = c->next) {
172 mvwin(c->w, c->top, 0);
173 wresize(c->w, c->height, COLS);
174 mvwin(c->s, c->top + c->height, 0);
175 wnoutrefresh(c->w);
176 wnoutrefresh(c->s);
177 }
178 doupdate();
37aa0f71 179#else
180 endwin();
181 wrefresh(curscr);
182#endif
63124806 183 errno = e;
3315e8b3 184}
185
186#endif
187
188/* --- @curses_ok@ --- */
189
190int curses_ok(void)
191{
192 if (!isatty(STDOUT_FILENO)) {
193 moan("can't use curses: stdout isn't a terminal");
194 return (0);
195 }
196 if (setupterm(0, STDOUT_FILENO, 0) == ERR) {
197 moan("can't use curses: couldn't read terminfo");
198 return (0);
199 }
200 if (!tigetstr("cup")) {
201 moan("can't use curses: terminal insufficiently winning");
202 return (0);
203 }
204 return (1);
205}
206
207/* --- @curses_init@ --- */
208
209int curses_init(archcons *a)
210{
211 cwin **cc = &cwins, *c;
212
213 /* --- Allocate my window structures --- */
214
215 nwins = 0;
216 for (; a; a = a->cdr) {
217 archent *e = a->car;
218 if (!e->r)
219 continue;
220 c = xmalloc(sizeof(cwin));
221 e->pres = c;
222 c->w = 0;
223 c->e = e;
224 nwins++;
225 *cc = c;
226 cc = &c->next;
227 }
228 *cc = 0;
229
230 /* --- Haul curses up by its naughty bits --- */
231
232 initscr();
233 keypad(stdscr, TRUE);
234 cbreak();
235 noecho();
236 nonl();
237 def_prog_mode();
238
239 /* --- Grind through everything setting up windows --- */
240
241 sizes();
242 for (c = cwins; c; c = c->next) {
243 if ((c->w = newwin(c->height, COLS, c->top, 0)) == 0 ||
244 (c->s = newwin(1, COLS, c->top + c->height, 0)) == 0)
245 goto fail_0;
246 scrollok(c->w, TRUE);
247 leaveok(c->w, TRUE);
248 leaveok(c->s, TRUE);
4840d4f1 249 wbkgd(c->s, A_STANDOUT);
5636c0ce 250 mvwprintw(c->s, 0, 0, " %s [running]\n", c->e->arch);
3315e8b3 251 wnoutrefresh(c->w);
252 wnoutrefresh(c->s);
253 }
254 doupdate();
255
c2f4ecb4 256#ifdef SIGWINCH
3315e8b3 257 signal(SIGWINCH, sig_winch);
258#endif
259#ifdef SIGTSTP
260 signal(SIGTSTP, sig_tstp);
261 signal(SIGCONT, sig_cont);
262#endif
263 return (0);
264
265fail_0:
266 c = cwins;
267 while (c) {
268 cwin *cc = c->next;
269 if (c->w)
270 delwin(c->w);
271 if (c->s)
272 delwin(c->s);
273 free(c);
274 c = cc;
275 }
276 endwin();
277 return (-1);
278}
279
280/* --- @curses_output@ --- */
281
282void curses_output(archent *e, const char *p, size_t sz)
283{
284 cwin *c = e->pres;
285 while (sz) {
286 waddch(c->w, *p);
287 p++;
288 sz--;
289 }
290 wrefresh(c->w);
291}
292
293/* --- @curses_close@ --- */
294
5636c0ce 295void curses_close(archent *e, int ok, const char *summ)
3315e8b3 296{
297 cwin *c = e->pres;
5636c0ce 298 mvwprintw(c->s, 0, 0, " %s [%s]\n", e->arch, summ);
3315e8b3 299 wrefresh(c->s);
300}
301
302/* --- @curses_done@ --- */
303
304void curses_done(archcons *a)
305{
306 if (opt_flags & optFlag_beep) {
307 beep();
308 doupdate();
309 }
310 wgetch(cwins->w);
311 cwins = 0;
312 for (; a; a = a->cdr) {
313 archent *e = a->car;
314 cwin *c = e->pres;
315 delwin(c->w);
316 delwin(c->s);
317 free(c);
318 }
319 curses_abort(0);
320}
321
322/* --- @curses_abort@ --- */
323
324void curses_abort(archcons *a)
325{
326#ifdef HAVE_WRESIZE
327 signal(SIGWINCH, SIG_DFL);
328#endif
329#ifdef SIGTSTP
330 signal(SIGTSTP, SIG_DFL);
331 signal(SIGCONT, SIG_DFL);
332#endif
333 endwin();
334}
335
336/*----- That's all, folks -------------------------------------------------*/
337
338#else
339 int pres_curses__built = 1;
340#endif