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