xref: /original-bsd/usr.bin/window/win.c (revision 5656414f)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * 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  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)win.c	3.24 (Berkeley) 06/06/90";
13 #endif /* not lint */
14 
15 #include "defs.h"
16 #include "char.h"
17 #ifdef POSIX_TTY
18 #include <sys/ioctl.h>
19 #endif
20 
21 /*
22  * Higher level routines for dealing with windows.
23  *
24  * There are two types of windows: user window, and information window.
25  * User windows are the ones with a pty and shell.  Information windows
26  * are for displaying error messages, and other information.
27  *
28  * The windows are doubly linked in overlapping order and divided into
29  * two groups: foreground and normal.  Information
30  * windows are always foreground.  User windows can be either.
31  * Addwin() adds a window to the list at the top of one of the two groups.
32  * Deletewin() deletes a window.  Front() moves a window to the front
33  * of its group.  Wwopen(), wwadd(), and wwdelete() should never be called
34  * directly.
35  */
36 
37 /*
38  * Open a user window.
39  */
40 struct ww *
41 openwin(id, row, col, nrow, ncol, nline, label, haspty, hasframe, shf, sh)
42 char *label;
43 char haspty, hasframe;
44 char *shf, **sh;
45 {
46 	register struct ww *w;
47 
48 	if (id < 0 && (id = findid()) < 0)
49 		return 0;
50 	if (row + nrow <= 0 || row > wwnrow - 1
51 	    || col + ncol <= 0 || col > wwncol - 1) {
52 		error("Illegal window position.");
53 		return 0;
54 	}
55 	w = wwopen(haspty ? WWO_PTY : WWO_SOCKET, nrow, ncol, row, col, nline);
56 	if (w == 0) {
57 		error("Can't open window: %s.", wwerror());
58 		return 0;
59 	}
60 	w->ww_id = id;
61 	window[id] = w;
62 	w->ww_hasframe = hasframe;
63 	w->ww_alt = w->ww_w;
64 	if (label != 0 && setlabel(w, label) < 0)
65 		error("No memory for label.");
66 	wwcursor(w, 1);
67 	/*
68 	 * We have to do this little maneuver to make sure
69 	 * addwin() puts w at the top, so we don't waste an
70 	 * insert and delete operation.
71 	 */
72 	setselwin((struct ww *)0);
73 	addwin(w, 0);
74 	setselwin(w);
75 	if (wwspawn(w, shf, sh) < 0) {
76 		error("Can't execute %s: %s.", shf, wwerror());
77 		closewin(w);
78 		return 0;
79 	}
80 	return w;
81 }
82 
83 findid()
84 {
85 	register i;
86 
87 	for (i = 0; i < NWINDOW && window[i] != 0; i++)
88 		;
89 	if (i >= NWINDOW) {
90 		error("Too many windows.");
91 		return -1;
92 	}
93 	return i;
94 }
95 
96 struct ww *
97 findselwin()
98 {
99 	register struct ww *w, *s = 0;
100 	register i;
101 
102 	for (i = 0; i < NWINDOW; i++)
103 		if ((w = window[i]) != 0 && w != selwin &&
104 		    (s == 0 ||
105 		     !isfg(w) && (w->ww_order < s->ww_order || isfg(s))))
106 			s = w;
107 	return s;
108 }
109 
110 /*
111  * Close a user window.  Close all if w == 0.
112  */
113 closewin(w)
114 register struct ww *w;
115 {
116 	char didit = 0;
117 	register i;
118 
119 	if (w != 0) {
120 		closewin1(w);
121 		didit++;
122 	} else
123 		for (i = 0; i < NWINDOW; i++) {
124 			if ((w = window[i]) == 0)
125 				continue;
126 			closewin1(w);
127 			didit++;
128 		}
129 	if (didit) {
130 		if (selwin == 0)
131 			if (lastselwin != 0) {
132 				setselwin(lastselwin);
133 				lastselwin = 0;
134 			} else if (w = findselwin())
135 				setselwin(w);
136 		if (lastselwin == 0 && selwin)
137 			if (w = findselwin())
138 				lastselwin = w;
139 		reframe();
140 	}
141 }
142 
143 /*
144  * Open an information (display) window.
145  */
146 struct ww *
147 openiwin(nrow, label)
148 char *label;
149 {
150 	register struct ww *w;
151 
152 	if ((w = wwopen(0, nrow, wwncol, 2, 0, 0)) == 0)
153 		return 0;
154 	w->ww_mapnl = 1;
155 	w->ww_hasframe = 1;
156 	w->ww_nointr = 1;
157 	w->ww_noupdate = 1;
158 	w->ww_unctrl = 1;
159 	w->ww_id = -1;
160 	w->ww_center = 1;
161 	(void) setlabel(w, label);
162 	addwin(w, 1);
163 	reframe();
164 	return w;
165 }
166 
167 /*
168  * Close an information window.
169  */
170 closeiwin(w)
171 struct ww *w;
172 {
173 	closewin1(w);
174 	reframe();
175 }
176 
177 closewin1(w)
178 register struct ww *w;
179 {
180 	if (w == selwin)
181 		selwin = 0;
182 	if (w == lastselwin)
183 		lastselwin = 0;
184 	if (w->ww_id >= 0 && w->ww_id < NWINDOW)
185 		window[w->ww_id] = 0;
186 	if (w->ww_label)
187 		str_free(w->ww_label);
188 	deletewin(w);
189 	wwclose(w);
190 }
191 
192 /*
193  * Move the window to the top of its group.
194  * Don't do it if already fully visible.
195  * Wwvisible() doesn't work for tinted windows.
196  * But anything to make it faster.
197  * Always reframe() if doreframe is true.
198  */
199 front(w, doreframe)
200 register struct ww *w;
201 char doreframe;
202 {
203 	if (w->ww_back != (isfg(w) ? framewin : fgwin) && !wwvisible(w)) {
204 		deletewin(w);
205 		addwin(w, isfg(w));
206 		doreframe = 1;
207 	}
208 	if (doreframe)
209 		reframe();
210 }
211 
212 /*
213  * Add a window at the top of normal windows or foreground windows.
214  * For normal windows, we put it behind the current window.
215  */
216 addwin(w, fg)
217 register struct ww *w;
218 char fg;
219 {
220 	if (fg) {
221 		wwadd(w, framewin);
222 		if (fgwin == framewin)
223 			fgwin = w;
224 	} else
225 		wwadd(w, selwin != 0 && selwin != w && !isfg(selwin)
226 				? selwin : fgwin);
227 }
228 
229 /*
230  * Delete a window.
231  */
232 deletewin(w)
233 register struct ww *w;
234 {
235 	if (fgwin == w)
236 		fgwin = w->ww_back;
237 	wwdelete(w);
238 }
239 
240 reframe()
241 {
242 	register struct ww *w;
243 
244 	wwunframe(framewin);
245 	for (w = wwhead.ww_back; w != &wwhead; w = w->ww_back)
246 		if (w->ww_hasframe) {
247 			wwframe(w, framewin);
248 			labelwin(w);
249 		}
250 }
251 
252 labelwin(w)
253 register struct ww *w;
254 {
255 	int mode = w == selwin ? WWM_REV : 0;
256 
257 	if (!w->ww_hasframe)
258 		return;
259 	if (w->ww_id >= 0) {
260 		char buf[2];
261 
262 		buf[0] = w->ww_id + '1';
263 		buf[1] = 0;
264 		wwlabel(w, framewin, 1, buf, mode);
265 	}
266 	if (w->ww_label) {
267 		int col;
268 
269 		if (w->ww_center) {
270 			col = (w->ww_w.nc - strlen(w->ww_label)) / 2;
271 			col = MAX(3, col);
272 		} else
273 			col = 3;
274 		wwlabel(w, framewin, col, w->ww_label, mode);
275 	}
276 }
277 
278 stopwin(w)
279 	register struct ww *w;
280 {
281 	w->ww_stopped = 1;
282 	if (w->ww_pty >= 0 && w->ww_ispty)
283 		(void) ioctl(w->ww_pty, TIOCSTOP, (char *)0);
284 }
285 
286 startwin(w)
287 	register struct ww *w;
288 {
289 	w->ww_stopped = 0;
290 	if (w->ww_pty >= 0 && w->ww_ispty)
291 		(void) ioctl(w->ww_pty, TIOCSTART, (char *)0);
292 }
293 
294 sizewin(w, nrow, ncol)
295 register struct ww *w;
296 {
297 	struct ww *back = w->ww_back;
298 
299 	w->ww_alt.nr = w->ww_w.nr;
300 	w->ww_alt.nc = w->ww_w.nc;
301 	wwdelete(w);
302 	if (wwsize(w, nrow, ncol) < 0)
303 		error("Can't resize window: %s.", wwerror());
304 	wwadd(w, back);
305 	reframe();
306 }
307 
308 waitnl(w)
309 struct ww *w;
310 {
311 	(void) waitnl1(w, "[Type any key to continue]");
312 }
313 
314 more(w, always)
315 register struct ww *w;
316 char always;
317 {
318 	int c;
319 	char uc = w->ww_unctrl;
320 
321 	if (!always && w->ww_cur.r < w->ww_w.b - 2)
322 		return 0;
323 	c = waitnl1(w, "[Type escape to abort, any other key to continue]");
324 	w->ww_unctrl = 0;
325 	wwputs("\033E", w);
326 	w->ww_unctrl = uc;
327 	return c == ctrl('[') ? 2 : 1;
328 }
329 
330 waitnl1(w, prompt)
331 register struct ww *w;
332 char *prompt;
333 {
334 	char uc = w->ww_unctrl;
335 
336 	w->ww_unctrl = 0;
337 	front(w, 0);
338 	wwprintf(w, "\033Y%c%c\033sA%s\033rA ",
339 		w->ww_w.nr - 1 + ' ', ' ', prompt);	/* print on last line */
340 	wwcurtowin(w);
341 	while (wwpeekc() < 0)
342 		wwiomux();
343 	w->ww_unctrl = uc;
344 	return wwgetc();
345 }
346