chiark / gitweb /
Fix typo in comment.
[sw-tools] / src / pres_curses.c
1 /* -*-c-*-
2  *
3  * $Id: pres_curses.c,v 1.6 1999/07/27 14:04:19 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.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
36  * Slight tidying of resizing terminal handling.
37  *
38  * Revision 1.4  1999/07/16  16:52:28  mdw
39  * `wbkdset' doesn't work so well.  Use `wbkgd' instead.
40  *
41  * Revision 1.3  1999/07/16 12:49:58  mdw
42  * Improve exit status display.  New interface from `doto' project.
43  *
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.
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
90 typedef 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
101 static cwin *cwins = 0;
102 static 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
119 static 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
137 static void sig_tstp(int s)
138 {
139   int e = errno;
140   endwin();
141   errno = e;
142   raise(SIGSTOP);
143 }
144 #endif
145
146 /* --- @sig_cont@ --- */
147
148 #ifdef SIGTSTP
149 static void sig_cont(int s)
150 {
151   int e = errno;
152   wrefresh(curscr);
153   errno = e;
154 }
155 #endif
156
157 /* --- @sig_winch@ --- */
158
159 #ifdef SIGWINCH
160
161 static void sig_winch(int s)
162 {
163   int e = errno;
164
165 #ifdef HAVE_WRESIZE
166   cwin *c;
167
168   endwin();
169   wrefresh(curscr);
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();
179 #else
180   endwin();
181   wrefresh(curscr);
182 #endif
183   errno = e;
184 }
185
186 #endif
187
188 /* --- @curses_ok@ --- */
189
190 int 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
209 int 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);
249     wbkgd(c->s, A_STANDOUT);
250     mvwprintw(c->s, 0, 0, "  %s [running]\n", c->e->arch);
251     wnoutrefresh(c->w);
252     wnoutrefresh(c->s);
253   }
254   doupdate();
255
256 #ifdef SIGWINCH
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
265 fail_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
282 void 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
295 void curses_close(archent *e, int ok, const char *summ)
296 {
297   cwin *c = e->pres;
298   mvwprintw(c->s, 0, 0, "  %s [%s]\n", e->arch, summ);
299   wrefresh(c->s);
300 }
301
302 /* --- @curses_done@ --- */
303
304 void 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
324 void 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