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