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