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