Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / window / win.c
1 /*
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Edward Wang at The University of California, Berkeley.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #ifndef lint
38 static char sccsid[] = "@(#)win.c       8.1 (Berkeley) 6/6/93";
39 static char rcsid[] =
40   "$FreeBSD: src/usr.bin/window/win.c,v 1.1.1.1.14.1 2001/05/17 09:45:01 obrien Exp $";
41 #endif /* not lint */
42
43 #include "defs.h"
44 #include "char.h"
45
46 /*
47  * Higher level routines for dealing with windows.
48  *
49  * There are two types of windows: user window, and information window.
50  * User windows are the ones with a pty and shell.  Information windows
51  * are for displaying error messages, and other information.
52  *
53  * The windows are doubly linked in overlapping order and divided into
54  * two groups: foreground and normal.  Information
55  * windows are always foreground.  User windows can be either.
56  * Addwin() adds a window to the list at the top of one of the two groups.
57  * Deletewin() deletes a window.  Front() moves a window to the front
58  * of its group.  Wwopen(), wwadd(), and wwdelete() should never be called
59  * directly.
60  */
61
62 /*
63  * Open a user window.
64  */
65 struct ww *
66 openwin(id, row, col, nrow, ncol, nline, label, haspty, hasframe, shf, sh)
67 char *label;
68 char haspty, hasframe;
69 char *shf, **sh;
70 {
71         register struct ww *w;
72
73         if (id < 0 && (id = findid()) < 0)
74                 return 0;
75         if (row + nrow <= 0 || row > wwnrow - 1
76             || col + ncol <= 0 || col > wwncol - 1) {
77                 error("Illegal window position.");
78                 return 0;
79         }
80         w = wwopen(haspty ? WWO_PTY : WWO_SOCKET, nrow, ncol, row, col, nline);
81         if (w == 0) {
82                 error("Can't open window: %s.", wwerror());
83                 return 0;
84         }
85         w->ww_id = id;
86         window[id] = w;
87         w->ww_hasframe = hasframe;
88         w->ww_alt = w->ww_w;
89         if (label != 0 && setlabel(w, label) < 0)
90                 error("No memory for label.");
91         wwcursor(w, 1);
92         /*
93          * We have to do this little maneuver to make sure
94          * addwin() puts w at the top, so we don't waste an
95          * insert and delete operation.
96          */
97         setselwin((struct ww *)0);
98         addwin(w, 0);
99         setselwin(w);
100         if (wwspawn(w, shf, sh) < 0) {
101                 error("Can't execute %s: %s.", shf, wwerror());
102                 closewin(w);
103                 return 0;
104         }
105         return w;
106 }
107
108 findid()
109 {
110         register i;
111
112         for (i = 0; i < NWINDOW && window[i] != 0; i++)
113                 ;
114         if (i >= NWINDOW) {
115                 error("Too many windows.");
116                 return -1;
117         }
118         return i;
119 }
120
121 struct ww *
122 findselwin()
123 {
124         register struct ww *w, *s = 0;
125         register i;
126
127         for (i = 0; i < NWINDOW; i++)
128                 if ((w = window[i]) != 0 && w != selwin &&
129                     (s == 0 ||
130                      !isfg(w) && (w->ww_order < s->ww_order || isfg(s))))
131                         s = w;
132         return s;
133 }
134
135 /*
136  * Close a user window.  Close all if w == 0.
137  */
138 closewin(w)
139 register struct ww *w;
140 {
141         char didit = 0;
142         register i;
143
144         if (w != 0) {
145                 closewin1(w);
146                 didit++;
147         } else
148                 for (i = 0; i < NWINDOW; i++) {
149                         if ((w = window[i]) == 0)
150                                 continue;
151                         closewin1(w);
152                         didit++;
153                 }
154         if (didit) {
155                 if (selwin == 0)
156                         if (lastselwin != 0) {
157                                 setselwin(lastselwin);
158                                 lastselwin = 0;
159                         } else if (w = findselwin())
160                                 setselwin(w);
161                 if (lastselwin == 0 && selwin)
162                         if (w = findselwin())
163                                 lastselwin = w;
164                 reframe();
165         }
166 }
167
168 /*
169  * Open an information (display) window.
170  */
171 struct ww *
172 openiwin(nrow, label)
173 char *label;
174 {
175         register struct ww *w;
176
177         if ((w = wwopen(0, nrow, wwncol, 2, 0, 0)) == 0)
178                 return 0;
179         w->ww_mapnl = 1;
180         w->ww_hasframe = 1;
181         w->ww_nointr = 1;
182         w->ww_noupdate = 1;
183         w->ww_unctrl = 1;
184         w->ww_id = -1;
185         w->ww_center = 1;
186         (void) setlabel(w, label);
187         addwin(w, 1);
188         reframe();
189         return w;
190 }
191
192 /*
193  * Close an information window.
194  */
195 closeiwin(w)
196 struct ww *w;
197 {
198         closewin1(w);
199         reframe();
200 }
201
202 closewin1(w)
203 register struct ww *w;
204 {
205         if (w == selwin)
206                 selwin = 0;
207         if (w == lastselwin)
208                 lastselwin = 0;
209         if (w->ww_id >= 0 && w->ww_id < NWINDOW)
210                 window[w->ww_id] = 0;
211         if (w->ww_label)
212                 str_free(w->ww_label);
213         deletewin(w);
214         wwclose(w);
215 }
216
217 /*
218  * Move the window to the top of its group.
219  * Don't do it if already fully visible.
220  * Wwvisible() doesn't work for tinted windows.
221  * But anything to make it faster.
222  * Always reframe() if doreframe is true.
223  */
224 front(w, doreframe)
225 register struct ww *w;
226 char doreframe;
227 {
228         if (w->ww_back != (isfg(w) ? framewin : fgwin) && !wwvisible(w)) {
229                 deletewin(w);
230                 addwin(w, isfg(w));
231                 doreframe = 1;
232         }
233         if (doreframe)
234                 reframe();
235 }
236
237 /*
238  * Add a window at the top of normal windows or foreground windows.
239  * For normal windows, we put it behind the current window.
240  */
241 addwin(w, fg)
242 register struct ww *w;
243 char fg;
244 {
245         if (fg) {
246                 wwadd(w, framewin);
247                 if (fgwin == framewin)
248                         fgwin = w;
249         } else
250                 wwadd(w, selwin != 0 && selwin != w && !isfg(selwin)
251                                 ? selwin : fgwin);
252 }
253
254 /*
255  * Delete a window.
256  */
257 deletewin(w)
258 register struct ww *w;
259 {
260         if (fgwin == w)
261                 fgwin = w->ww_back;
262         wwdelete(w);
263 }
264
265 reframe()
266 {
267         register struct ww *w;
268
269         wwunframe(framewin);
270         for (w = wwhead.ww_back; w != &wwhead; w = w->ww_back)
271                 if (w->ww_hasframe) {
272                         wwframe(w, framewin);
273                         labelwin(w);
274                 }
275 }
276
277 labelwin(w)
278 register struct ww *w;
279 {
280         int mode = w == selwin ? WWM_REV : 0;
281
282         if (!w->ww_hasframe)
283                 return;
284         if (w->ww_id >= 0) {
285                 char buf[2];
286
287                 buf[0] = w->ww_id + '1';
288                 buf[1] = 0;
289                 wwlabel(w, framewin, 1, buf, mode);
290         }
291         if (w->ww_label) {
292                 int col;
293
294                 if (w->ww_center) {
295                         col = (w->ww_w.nc - strlen(w->ww_label)) / 2;
296                         col = MAX(3, col);
297                 } else
298                         col = 3;
299                 wwlabel(w, framewin, col, w->ww_label, mode);
300         }
301 }
302
303 stopwin(w)
304         register struct ww *w;
305 {
306         if (w->ww_pty >= 0 && w->ww_ispty && wwstoptty(w->ww_pty) < 0)
307                 error("Can't stop output: %s.", wwerror());
308         else
309                 w->ww_stopped = 1;
310 }
311
312 startwin(w)
313         register struct ww *w;
314 {
315         if (w->ww_pty >= 0 && w->ww_ispty && wwstarttty(w->ww_pty) < 0)
316                 error("Can't start output: %s.", wwerror());
317         else
318                 w->ww_stopped = 0;
319 }
320
321 sizewin(w, nrow, ncol)
322 register struct ww *w;
323 {
324         struct ww *back = w->ww_back;
325
326         w->ww_alt.nr = w->ww_w.nr;
327         w->ww_alt.nc = w->ww_w.nc;
328         wwdelete(w);
329         if (wwsize(w, nrow, ncol) < 0)
330                 error("Can't resize window: %s.", wwerror());
331         wwadd(w, back);
332         reframe();
333 }
334
335 waitnl(w)
336 struct ww *w;
337 {
338         (void) waitnl1(w, "[Type any key to continue]");
339 }
340
341 more(w, always)
342 register struct ww *w;
343 char always;
344 {
345         int c;
346         char uc = w->ww_unctrl;
347
348         if (!always && w->ww_cur.r < w->ww_w.b - 2)
349                 return 0;
350         c = waitnl1(w, "[Type escape to abort, any other key to continue]");
351         w->ww_unctrl = 0;
352         wwputs("\033E", w);
353         w->ww_unctrl = uc;
354         return c == ctrl('[') ? 2 : 1;
355 }
356
357 waitnl1(w, prompt)
358 register struct ww *w;
359 char *prompt;
360 {
361         char uc = w->ww_unctrl;
362
363         w->ww_unctrl = 0;
364         front(w, 0);
365         wwprintf(w, "\033Y%c%c\033sA%s\033rA ",
366                 w->ww_w.nr - 1 + ' ', ' ', prompt);     /* print on last line */
367         wwcurtowin(w);
368         while (wwpeekc() < 0)
369                 wwiomux();
370         w->ww_unctrl = uc;
371         return wwgetc();
372 }