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