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