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