1 /* $Id: window.c,v 1.2 2001/05/25 15:36:53 amura Exp $ */
2 /*
3  *		Window handling.
4  */
5 
6 /*
7  * $Log: window.c,v $
8  * Revision 1.2  2001/05/25 15:36:53  amura
9  * now buffers have only one mark (before windows have one mark)
10  *
11  * Revision 1.1.1.1  2000/06/27 01:47:55  amura
12  * import to CVS
13  *
14  */
15 
16 #include	"config.h"	/* 90.12.20  by S.Yoshida */
17 #include	"def.h"
18 
19 /*
20  * Reposition dot in the current
21  * window to line "n". If the argument is
22  * positive, it is that line. If it is negative it
23  * is that line from the bottom. If it is 0 the window
24  * is centered (this is what the standard redisplay code
25  * does).  If GOSREC is undefined, default is 0, so it acts like GNU.
26  * If GOSREC is defined, with no argument it defaults to 1
27  * and works like in Gosling.
28  */
29 /*ARGSUSED*/
reposition(f,n)30 reposition(f, n)
31 {
32 #ifndef GOSREC
33 	curwp->w_force = (f & FFARG) ? (n>=0 ? n+1 : n) : 0;
34 #else
35 	curwp->w_force = n;
36 #endif
37 	curwp->w_flag |= WFFORCE;
38 	sgarbf = TRUE;
39 	return TRUE;
40 }
41 
42 /*
43  * Refresh the display. A call is made to the
44  * "ttresize" entry in the terminal handler, which tries
45  * to reset "nrow" and "ncol". They will, however, never
46  * be set outside of the NROW or NCOL range. If the display
47  * changed size, arrange that everything is redone, then
48  * call "update" to fix the display. We do this so the
49  * new size can be displayed. In the normal case the
50  * call to "update" in "main.c" refreshes the screen,
51  * and all of the windows need not be recomputed.
52  * Note that when you get to the "display unusable"
53  * message, the screen will be messed up. If you make
54  * the window bigger again, and send another command,
55  * everything will get fixed!
56  */
57 /*ARGSUSED*/
refresh(f,n)58 refresh(f, n)
59 {
60 	register WINDOW *wp;
61 	register int	oldnrow;
62 	register int	oldncol;
63 
64 	oldnrow = nrow;
65 	oldncol = ncol;
66 	ttresize();
67 	if (nrow!=oldnrow || ncol!=oldncol) {
68 		wp = wheadp;			/* Find last.		*/
69 		while (wp->w_wndp != NULL)
70 			wp = wp->w_wndp;
71 		if (nrow < wp->w_toprow+3) {	/* Check if too small.	*/
72 			ewprintf("Display unusable");
73 			return (FALSE);
74 		}
75 		wp->w_ntrows = nrow-wp->w_toprow-2;
76 		sgarbf = TRUE;
77 		update();
78 		ewprintf("New size %d by %d", nrow, ncol);
79 	} else
80 		sgarbf = TRUE;
81 	return TRUE;
82 }
83 
84 /*
85  * The command to make the next
86  * window (next => down the screen)
87  * the current window. There are no real
88  * errors, although the command does
89  * nothing if there is only 1 window on
90  * the screen.
91  */
92 /*ARGSUSED*/
nextwind(f,n)93 nextwind(f, n)
94 {
95 	register WINDOW *wp;
96 
97 	if ((wp=curwp->w_wndp) == NULL)
98 		wp = wheadp;
99 	curwp = wp;
100 	curbp = wp->w_bufp;
101 	return TRUE;
102 }
103 
104 #ifdef	GOSMACS
105 /* not in Gnu Emacs */
106 /*
107  * This command makes the previous
108  * window (previous => up the screen) the
109  * current window. There arn't any errors,
110  * although the command does not do a lot
111  * if there is 1 window.
112  */
113 /*ARGSUSED*/
prevwind(f,n)114 prevwind(f, n)
115 {
116 	register WINDOW *wp1;
117 	register WINDOW *wp2;
118 
119 	wp1 = wheadp;
120 	wp2 = curwp;
121 	if (wp1 == wp2)
122 		wp2 = NULL;
123 	while (wp1->w_wndp != wp2)
124 		wp1 = wp1->w_wndp;
125 	curwp = wp1;
126 	curbp = wp1->w_bufp;
127 	return TRUE;
128 }
129 #endif
130 
131 /*
132  * This command makes the current
133  * window the only window on the screen.
134  * Try to set the framing
135  * so that "." does not have to move on
136  * the display. Some care has to be taken
137  * to keep the values of dot and mark
138  * in the buffer structures right if the
139  * distruction of a window makes a buffer
140  * become undisplayed.
141  */
142 /*ARGSUSED*/
onlywind(f,n)143 onlywind(f, n)
144 {
145 	register WINDOW *wp;
146 	register LINE	*lp;
147 	register int	i;
148 
149 	while (wheadp != curwp) {
150 		wp = wheadp;
151 		wheadp = wp->w_wndp;
152 		if (--wp->w_bufp->b_nwnd == 0) {
153 			wp->w_bufp->b_dotp  = wp->w_dotp;
154 			wp->w_bufp->b_doto  = wp->w_doto;
155 		}
156 		free((char *) wp);
157 	}
158 	while (curwp->w_wndp != NULL) {
159 		wp = curwp->w_wndp;
160 		curwp->w_wndp = wp->w_wndp;
161 		if (--wp->w_bufp->b_nwnd == 0) {
162 			wp->w_bufp->b_dotp  = wp->w_dotp;
163 			wp->w_bufp->b_doto  = wp->w_doto;
164 		}
165 		free((char *) wp);
166 	}
167 	lp = curwp->w_linep;
168 	i  = curwp->w_toprow - curwp->w_lines;
169 	while (i>0 && lback(lp)!=curbp->b_linep) {
170 		lp = lback(lp);
171 		i -= countlines(lp);
172 	}
173 	if (i > 0) i = 0;
174 	if (i < 0) i = -i;
175 	curwp->w_toprow = 0;
176 	curwp->w_ntrows = nrow-2;		/* 2 = mode, echo.	*/
177 	curwp->w_linep	= lp;
178 	curwp->w_lines = i;
179 	curwp->w_flag  |= WFMODE|WFHARD;
180 	return TRUE;
181 }
182 
183 /*
184  * Split the current window. A window
185  * smaller than 3 lines cannot be split.
186  * The only other error that is possible is
187  * a "malloc" failure allocating the structure
188  * for the new window.
189  */
190 /*ARGSUSED*/
splitwind(f,n)191 splitwind(f, n)
192 {
193 	register WINDOW *wp;
194 	register LINE	*lp;
195 	register int	ntru;
196 	register int	ntrd;
197 	int		ntrl;
198 	int		lines;
199 	WINDOW		*wp1, *wp2;
200 
201 	if (curwp->w_ntrows < 3) {
202 		ewprintf("Cannot split a %d line window", curwp->w_ntrows);
203 		return (FALSE);
204 	}
205 	if ((wp = (WINDOW *)malloc(sizeof(WINDOW))) == NULL) {
206 		ewprintf("Can't get %d", sizeof(WINDOW));
207 		return (FALSE);
208 	}
209 	++curbp->b_nwnd;			/* Displayed twice.	*/
210 	wp->w_bufp  = curbp;
211 	wp->w_dotp  = curwp->w_dotp;
212 	wp->w_doto  = curwp->w_doto;
213 	wp->w_flag  = 0;
214 	wp->w_force = 0;
215 	ntru = (curwp->w_ntrows-1) / 2;		/* Upper size		*/
216 	ntrl = (curwp->w_ntrows-1) - ntru;	/* Lower size		*/
217 	lp = curwp->w_linep;
218 	ntrd = - curwp->w_lines;
219 	while (lp != curwp->w_dotp) {
220 		ntrd += countlines(lp);
221 		lp = lforw(lp);
222 	}
223 	{
224 		int	x,y;
225 		ntrd += colrow(lp, curwp->w_doto, &x, &y);
226 	}
227 	lp = curwp->w_linep;
228 	lines = curwp->w_lines;
229 	if (ntrd <= ntru) {			/* Old is upper window. */
230 		if (ntrd == ntru) {		/* Hit mode line.	*/
231 			if ( countlines(lp) > lines+1 ) {
232 				++lines;
233 			} else {
234 				lp = lforw(lp);
235 				lines=0;
236 			}
237 		}
238 		curwp->w_ntrows = ntru;
239 		wp->w_wndp = curwp->w_wndp;
240 		curwp->w_wndp = wp;
241 		wp->w_toprow = curwp->w_toprow+ntru+1;
242 		wp->w_ntrows = ntrl;
243 	} else {				/* Old is lower window	*/
244 		wp1 = NULL;
245 		wp2 = wheadp;
246 		while (wp2 != curwp) {
247 			wp1 = wp2;
248 			wp2 = wp2->w_wndp;
249 		}
250 		if (wp1 == NULL)
251 			wheadp = wp;
252 		else
253 			wp1->w_wndp = wp;
254 		wp->w_wndp   = curwp;
255 		wp->w_toprow = curwp->w_toprow;
256 		wp->w_ntrows = ntru;
257 		++ntru;				/* Mode line.		*/
258 		curwp->w_toprow += ntru;
259 		curwp->w_ntrows	 = ntrl;
260 		ntru += lines;
261 		while (ntru > 0) {
262 			ntru -= countlines(lp);
263 			if (ntru < 0) break;
264 			lp = lforw(lp);
265 		}
266 		if (ntru < 0) ntru = countlines(lp) + ntru;
267 		lines = ntru;
268 	}
269 	curwp->w_linep = lp;			/* Adjust the top lines */
270 	wp->w_linep = lp;			/* if necessary.	*/
271 	curwp->w_lines = lines;
272 	wp->w_lines = lines;
273 	curwp->w_flag |= WFMODE|WFHARD;
274 	wp->w_flag |= WFMODE|WFHARD;
275 	return TRUE;
276 }
277 
278 /*
279  * Enlarge the current window.
280  * Find the window that loses space. Make
281  * sure it is big enough. If so, hack the window
282  * descriptions, and ask redisplay to do all the
283  * hard work. You don't just set "force reframe"
284  * because dot would move.
285  */
286 /*ARGSUSED*/
enlargewind(f,n)287 enlargewind(f, n)
288 {
289 	register WINDOW *adjwp;
290 	register LINE	*lp;
291 	register int	i;
292 
293 	if (n < 0)
294 		return shrinkwind(f, -n);
295 	if (wheadp->w_wndp == NULL) {
296 		ewprintf("Only one window");
297 		return FALSE;
298 	}
299 	if ((adjwp=curwp->w_wndp) == NULL) {
300 		adjwp = wheadp;
301 		while (adjwp->w_wndp != curwp)
302 			adjwp = adjwp->w_wndp;
303 	}
304 	if (adjwp->w_ntrows <= n) {
305 		ewprintf("Impossible change");
306 		return FALSE;
307 	}
308 	if (curwp->w_wndp == adjwp) {		/* Shrink below.	*/
309 		lp = adjwp->w_linep;
310 		for (i=n+adjwp->w_lines; i>0 && lp!=adjwp->w_bufp->b_linep; ) {
311 			i -= countlines(lp);
312 			if (i < 0) break;
313 			lp = lforw(lp);
314 		}
315 		if (i>0) i=countlines(lp)-1;	/* LAST row */
316 		if (i<0) i=countlines(lp)+i;
317 		adjwp->w_linep	= lp;
318 		adjwp->w_lines = i;
319 		adjwp->w_toprow += n;
320 	} else {				/* Shrink above.	*/
321 		lp = curwp->w_linep;
322 		for (i=n-curwp->w_lines; i>0 && lback(lp)!=curbp->b_linep; ){
323 			lp = lback(lp);
324 			i -= countlines(lp);
325 		}
326 		if (i>0) i= 0;
327 		if (i<0) i= -i;
328 		curwp->w_linep	= lp;
329 		curwp->w_lines = i;
330 		curwp->w_toprow -= n;
331 	}
332 	curwp->w_ntrows += n;
333 	adjwp->w_ntrows -= n;
334 	curwp->w_flag |= WFMODE|WFHARD;
335 	adjwp->w_flag |= WFMODE|WFHARD;
336 	return TRUE;
337 }
338 
339 /*
340  * Shrink the current window.
341  * Find the window that gains space. Hack at
342  * the window descriptions. Ask the redisplay to
343  * do all the hard work.
344  */
shrinkwind(f,n)345 shrinkwind(f, n)
346 {
347 	register WINDOW *adjwp;
348 	register LINE	*lp;
349 	register int	i;
350 
351 	if (n < 0)
352 		return enlargewind(f, -n);
353 	if (wheadp->w_wndp == NULL) {
354 		ewprintf("Only one window");
355 		return FALSE;
356 	}
357 	/*
358 	 * Bit of flakiness - KRANDOM means it was an internal call, and
359 	 * to be trusted implicitly about sizes.
360 	 */
361 	if ( !(f & FFRAND) && curwp->w_ntrows <= n) {
362 		ewprintf("Impossible change");
363 		return (FALSE);
364 	}
365 	if ((adjwp=curwp->w_wndp) == NULL) {
366 		adjwp = wheadp;
367 		while (adjwp->w_wndp != curwp)
368 			adjwp = adjwp->w_wndp;
369 	}
370 	if (curwp->w_wndp == adjwp) {		/* Grow below.		*/
371 		lp = adjwp->w_linep;
372 		for (i=n-adjwp->w_lines;
373 			i>0 && lback(lp)!=adjwp->w_bufp->b_linep; ) {
374 			lp = lback(lp);
375 			i -= countlines(lp);
376 		}
377 		if (i>0) i = 0;
378 		if (i<0) i = -i;
379 		adjwp->w_linep	= lp;
380 		adjwp->w_lines = i;
381 		adjwp->w_toprow -= n;
382 	} else {				/* Grow above.		*/
383 		lp = curwp->w_linep;
384 		for (i=n + curwp->w_lines; i>0 && lp!=curbp->b_linep;) {
385 			i -= countlines(lp);
386 			if (i<0) break;
387 			lp = lforw(lp);
388 		}
389 		if (i>0) i=countlines(lp)-1;	/* LAST row */
390 		if (i<0) i=countlines(lp)+i;
391 		curwp->w_linep	= lp;
392 		curwp->w_lines = i;
393 		curwp->w_toprow += n;
394 	}
395 	curwp->w_ntrows -= n;
396 	adjwp->w_ntrows += n;
397 	curwp->w_flag |= WFMODE|WFHARD;
398 	adjwp->w_flag |= WFMODE|WFHARD;
399 	return (TRUE);
400 }
401 
402 /*
403  * Delete current window. Call shrink-window to do the screen
404  * updating, then throw away the window.
405  */
406 /*ARGSUSED*/
delwind(f,n)407 delwind(f, n)
408 {
409 	register WINDOW *wp, *nwp;
410 
411 	wp = curwp;			/* Cheap...		*/
412 	/* shrinkwind returning false means only one window... */
413 	if (shrinkwind(FFRAND, wp->w_ntrows + 1) == FALSE)
414 		return FALSE;
415 	if (--wp->w_bufp->b_nwnd == 0) {
416 		wp->w_bufp->b_dotp  = wp->w_dotp;
417 		wp->w_bufp->b_doto  = wp->w_doto;
418 	}
419 	/* since shrinkwind did't crap out, we know we have a second window */
420 	if (wp == wheadp) wheadp = curwp = wp->w_wndp;
421 	else if ((curwp = wp->w_wndp) == NULL) curwp = wheadp;
422 	curbp = curwp->w_bufp;
423 	for (nwp = wheadp; nwp != NULL; nwp = nwp->w_wndp)
424 		if (nwp->w_wndp == wp) {
425 			nwp->w_wndp = wp->w_wndp;
426 			break ;
427 		}
428 	free((char *) wp);
429 	return TRUE;
430 }
431 /*
432  * Pick a window for a pop-up.
433  * Split the screen if there is only
434  * one window. Pick the uppermost window that
435  * isn't the current window. An LRU algorithm
436  * might be better. Return a pointer, or
437  * NULL on error.
438  */
439 WINDOW	*
wpopup()440 wpopup() {
441 	register WINDOW *wp;
442 
443 	if (wheadp->w_wndp == NULL
444 	&& splitwind(FFRAND, 0) == FALSE)
445 		return NULL;
446 	wp = wheadp;				/* Find window to use	*/
447 	while (wp!=NULL && wp==curwp)
448 		wp = wp->w_wndp;
449 	return wp;
450 }
451