First proper release version.
[sw-tools] / src / pres_curses.c
CommitLineData
3315e8b3 1/* -*-c-*-
2 *
63124806 3 * $Id: pres_curses.c,v 1.2 1999/06/24 15:51:16 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 $
63124806 32 * Revision 1.2 1999/06/24 15:51:16 mdw
33 * Fix signal handlers so they don't corrupt `errno'.
34 *
35 * Revision 1.1.1.1 1999/06/02 16:53:35 mdw
36 * Initial import.
3315e8b3 37 *
38 */
39
40/*----- Header files ------------------------------------------------------*/
41
42#include "config.h"
43#ifdef HAVE_CURSES
44
45#include <errno.h>
46#include <signal.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50
51#include <sys/types.h>
52#include <unistd.h>
53
54#if defined(HAVE_NCURSES_H)
55# include <ncurses.h>
56#elif defined(HAVE_NCURSES_NCURSES_H)
57# include <ncurses/ncurses.h>
58#elif defined(HAVE_CURSES_H)
59# include <curses.h>
60#else
61# error "Where's your <curses.h> header?"
62#endif
63#include <term.h>
64
65#include <mLib/alloc.h>
66#include <mLib/report.h>
67
68#include "sw.h"
69#include "sw_arch.h"
70#include "pres_curses.h"
71
72#ifndef SIGWINCH
73# undef HAVE_WRESIZE
74#endif
75
76/*----- Data structures ---------------------------------------------------*/
77
78typedef struct cwin {
79 struct cwin *next;
80 WINDOW *w;
81 int top;
82 int height;
83 WINDOW *s;
84 archent *e;
85} cwin;
86
87/*----- Static variables --------------------------------------------------*/
88
89static cwin *cwins = 0;
90static int nwins = 0;
91
92/*----- Main code ---------------------------------------------------------*/
93
94/* --- @sizes@ --- *
95 *
96 * Arguments: ---
97 *
98 * Returns: ---
99 *
100 * Use: Calculates window sizes for all the windows. The heights are
101 * determined in a way which doesn't allow rounding errors to be
102 * an issue (although there will be up to a line's height
103 * difference between two windows). No actual changing of
104 * curses structures is done.
105 */
106
107static void sizes(void)
108{
109 cwin *c;
110 int t = 0, h = LINES, w = nwins;
111
112 for (c = cwins; c; c = c->next) {
113 int a = h / w;
114 c->top = t;
115 c->height = a - 1;
116 t += a;
117 h -= a;
118 w--;
119 }
120}
121
122/* --- @sig_tstp@ --- */
123
124#ifdef SIGTSTP
125static void sig_tstp(int s)
126{
63124806 127 int e = errno;
3315e8b3 128 endwin();
63124806 129 errno = e;
3315e8b3 130 raise(SIGSTOP);
131}
132#endif
133
134/* --- @sig_cont@ --- */
135
136#ifdef SIGTSTP
137static void sig_cont(int s)
138{
63124806 139 int e = errno;
3315e8b3 140 wrefresh(curscr);
63124806 141 errno = e;
3315e8b3 142}
143#endif
144
145/* --- @sig_winch@ --- */
146
147#ifdef HAVE_WRESIZE
148
149static void sig_winch(int s)
150{
151 cwin *c;
63124806 152 int e = errno;
153
3315e8b3 154 endwin();
155 refresh();
156 sizes();
157 for (c = cwins; c; c = c->next) {
158 mvwin(c->w, c->top, 0);
159 wresize(c->w, c->height, COLS);
160 mvwin(c->s, c->top + c->height, 0);
161 wnoutrefresh(c->w);
162 wnoutrefresh(c->s);
163 }
164 doupdate();
63124806 165 errno = e;
3315e8b3 166}
167
168#endif
169
170/* --- @curses_ok@ --- */
171
172int curses_ok(void)
173{
174 if (!isatty(STDOUT_FILENO)) {
175 moan("can't use curses: stdout isn't a terminal");
176 return (0);
177 }
178 if (setupterm(0, STDOUT_FILENO, 0) == ERR) {
179 moan("can't use curses: couldn't read terminfo");
180 return (0);
181 }
182 if (!tigetstr("cup")) {
183 moan("can't use curses: terminal insufficiently winning");
184 return (0);
185 }
186 return (1);
187}
188
189/* --- @curses_init@ --- */
190
191int curses_init(archcons *a)
192{
193 cwin **cc = &cwins, *c;
194
195 /* --- Allocate my window structures --- */
196
197 nwins = 0;
198 for (; a; a = a->cdr) {
199 archent *e = a->car;
200 if (!e->r)
201 continue;
202 c = xmalloc(sizeof(cwin));
203 e->pres = c;
204 c->w = 0;
205 c->e = e;
206 nwins++;
207 *cc = c;
208 cc = &c->next;
209 }
210 *cc = 0;
211
212 /* --- Haul curses up by its naughty bits --- */
213
214 initscr();
215 keypad(stdscr, TRUE);
216 cbreak();
217 noecho();
218 nonl();
219 def_prog_mode();
220
221 /* --- Grind through everything setting up windows --- */
222
223 sizes();
224 for (c = cwins; c; c = c->next) {
225 if ((c->w = newwin(c->height, COLS, c->top, 0)) == 0 ||
226 (c->s = newwin(1, COLS, c->top + c->height, 0)) == 0)
227 goto fail_0;
228 scrollok(c->w, TRUE);
229 leaveok(c->w, TRUE);
230 leaveok(c->s, TRUE);
231 wbkgdset(c->s, A_STANDOUT);
232 werase(c->s);
233 mvwprintw(c->s, 0, 0, " %s [running]\n", c->e->arch);
234 wnoutrefresh(c->w);
235 wnoutrefresh(c->s);
236 }
237 doupdate();
238
239#ifdef HAVE_WRESIZE
240 signal(SIGWINCH, sig_winch);
241#endif
242#ifdef SIGTSTP
243 signal(SIGTSTP, sig_tstp);
244 signal(SIGCONT, sig_cont);
245#endif
246 return (0);
247
248fail_0:
249 c = cwins;
250 while (c) {
251 cwin *cc = c->next;
252 if (c->w)
253 delwin(c->w);
254 if (c->s)
255 delwin(c->s);
256 free(c);
257 c = cc;
258 }
259 endwin();
260 return (-1);
261}
262
263/* --- @curses_output@ --- */
264
265void curses_output(archent *e, const char *p, size_t sz)
266{
267 cwin *c = e->pres;
268 while (sz) {
269 waddch(c->w, *p);
270 p++;
271 sz--;
272 }
273 wrefresh(c->w);
274}
275
276/* --- @curses_close@ --- */
277
278void curses_close(archent *e, int ok)
279{
280 cwin *c = e->pres;
281 mvwprintw(c->s, 0, 0, " %s [%s]\n", e->arch, ok ? "finished" : "failed");
282 wrefresh(c->s);
283}
284
285/* --- @curses_done@ --- */
286
287void curses_done(archcons *a)
288{
289 if (opt_flags & optFlag_beep) {
290 beep();
291 doupdate();
292 }
293 wgetch(cwins->w);
294 cwins = 0;
295 for (; a; a = a->cdr) {
296 archent *e = a->car;
297 cwin *c = e->pres;
298 delwin(c->w);
299 delwin(c->s);
300 free(c);
301 }
302 curses_abort(0);
303}
304
305/* --- @curses_abort@ --- */
306
307void curses_abort(archcons *a)
308{
309#ifdef HAVE_WRESIZE
310 signal(SIGWINCH, SIG_DFL);
311#endif
312#ifdef SIGTSTP
313 signal(SIGTSTP, SIG_DFL);
314 signal(SIGCONT, SIG_DFL);
315#endif
316 endwin();
317}
318
319/*----- That's all, folks -------------------------------------------------*/
320
321#else
322 int pres_curses__built = 1;
323#endif