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