Annotation of src/usr.bin/mg/window.c, Revision 1.30
1.30 ! lum 1: /* $OpenBSD: window.c,v 1.29 2013/05/31 18:03:45 lum 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.30 ! lum 95: dobeep();
1.1 deraadt 96: ewprintf("Display unusable");
97: return (FALSE);
98: }
1.3 millert 99: wp->w_ntrows = nrow - wp->w_toprow - 2;
1.1 deraadt 100: sgarbf = TRUE;
1.29 lum 101: update(CMODE);
1.1 deraadt 102: } else
103: sgarbf = TRUE;
1.16 db 104: return (TRUE);
1.1 deraadt 105: }
106:
107: /*
1.7 mickey 108: * The command to make the next window (next => down the screen) the current
109: * window. There are no real errors, although the command does nothing if
1.4 millert 110: * there is only 1 window on the screen.
1.1 deraadt 111: */
1.3 millert 112: /* ARGSUSED */
1.4 millert 113: int
1.11 cloder 114: nextwind(int f, int n)
1.1 deraadt 115: {
1.19 deraadt 116: struct mgwin *wp;
1.1 deraadt 117:
1.3 millert 118: if ((wp = curwp->w_wndp) == NULL)
1.1 deraadt 119: wp = wheadp;
120: curwp = wp;
121: curbp = wp->w_bufp;
1.16 db 122: return (TRUE);
1.1 deraadt 123: }
124:
1.28 lum 125: /* not in GNU Emacs */
1.1 deraadt 126: /*
1.4 millert 127: * This command makes the previous window (previous => up the screen) the
1.7 mickey 128: * current window. There are no errors, although the command does not do
1.4 millert 129: * a lot if there is only 1 window.
1.1 deraadt 130: */
1.3 millert 131: /* ARGSUSED */
1.4 millert 132: int
1.11 cloder 133: prevwind(int f, int n)
1.1 deraadt 134: {
1.19 deraadt 135: struct mgwin *wp1, *wp2;
1.1 deraadt 136:
137: wp1 = wheadp;
138: wp2 = curwp;
139: if (wp1 == wp2)
140: wp2 = NULL;
141: while (wp1->w_wndp != wp2)
142: wp1 = wp1->w_wndp;
143: curwp = wp1;
144: curbp = wp1->w_bufp;
1.16 db 145: return (TRUE);
1.1 deraadt 146: }
147:
148: /*
1.7 mickey 149: * This command makes the current window the only window on the screen. Try
150: * to set the framing so that "." does not have to move on the display. Some
151: * care has to be taken to keep the values of dot and mark in the buffer
1.16 db 152: * structures right if the destruction of a window makes a buffer become
1.4 millert 153: * undisplayed.
1.1 deraadt 154: */
1.3 millert 155: /* ARGSUSED */
1.4 millert 156: int
1.11 cloder 157: onlywind(int f, int n)
1.1 deraadt 158: {
1.19 deraadt 159: struct mgwin *wp;
160: struct line *lp;
161: int i;
1.1 deraadt 162:
163: while (wheadp != curwp) {
164: wp = wheadp;
165: wheadp = wp->w_wndp;
166: if (--wp->w_bufp->b_nwnd == 0) {
1.3 millert 167: wp->w_bufp->b_dotp = wp->w_dotp;
168: wp->w_bufp->b_doto = wp->w_doto;
1.1 deraadt 169: wp->w_bufp->b_markp = wp->w_markp;
170: wp->w_bufp->b_marko = wp->w_marko;
171: }
1.18 kjell 172: free(wp);
1.1 deraadt 173: }
174: while (curwp->w_wndp != NULL) {
175: wp = curwp->w_wndp;
176: curwp->w_wndp = wp->w_wndp;
177: if (--wp->w_bufp->b_nwnd == 0) {
1.3 millert 178: wp->w_bufp->b_dotp = wp->w_dotp;
179: wp->w_bufp->b_doto = wp->w_doto;
1.1 deraadt 180: wp->w_bufp->b_markp = wp->w_markp;
181: wp->w_bufp->b_marko = wp->w_marko;
182: }
1.18 kjell 183: free(wp);
1.1 deraadt 184: }
185: lp = curwp->w_linep;
1.3 millert 186: i = curwp->w_toprow;
1.25 kjell 187: while (i != 0 && lback(lp) != curbp->b_headp) {
1.1 deraadt 188: --i;
189: lp = lback(lp);
190: }
191: curwp->w_toprow = 0;
1.4 millert 192:
193: /* 2 = mode, echo */
194: curwp->w_ntrows = nrow - 2;
1.3 millert 195: curwp->w_linep = lp;
1.26 kjell 196: curwp->w_rflag |= WFMODE | WFFULL;
1.16 db 197: return (TRUE);
1.1 deraadt 198: }
199:
200: /*
1.4 millert 201: * Split the current window. A window smaller than 3 lines cannot be split.
1.7 mickey 202: * The only other error that is possible is a "malloc" failure allocating the
1.4 millert 203: * structure for the new window.
1.27 kjell 204: * If called with a FFOTHARG, flags on the new window are set to 'n'.
1.1 deraadt 205: */
1.3 millert 206: /* ARGSUSED */
1.4 millert 207: int
1.11 cloder 208: splitwind(int f, int n)
1.1 deraadt 209: {
1.19 deraadt 210: struct mgwin *wp, *wp1, *wp2;
211: struct line *lp;
212: int ntru, ntrd, ntrl;
1.1 deraadt 213:
214: if (curwp->w_ntrows < 3) {
1.30 ! lum 215: dobeep();
1.1 deraadt 216: ewprintf("Cannot split a %d line window", curwp->w_ntrows);
217: return (FALSE);
218: }
1.12 vincent 219: wp = new_window(curbp);
220: if (wp == NULL) {
1.30 ! lum 221: dobeep();
1.12 vincent 222: ewprintf("Unable to create a window");
1.1 deraadt 223: return (FALSE);
224: }
1.4 millert 225:
1.12 vincent 226: /* use the current dot and mark */
1.3 millert 227: wp->w_dotp = curwp->w_dotp;
228: wp->w_doto = curwp->w_doto;
1.1 deraadt 229: wp->w_markp = curwp->w_markp;
230: wp->w_marko = curwp->w_marko;
1.24 kjell 231: wp->w_dotline = curwp->w_dotline;
232: wp->w_markline = curwp->w_markline;
1.12 vincent 233:
234: /* figure out which half of the screen we're in */
235: ntru = (curwp->w_ntrows - 1) / 2; /* Upper size */
236: ntrl = (curwp->w_ntrows - 1) - ntru; /* Lower size */
237:
238: for (lp = curwp->w_linep, ntrd = 0; lp != curwp->w_dotp;
239: lp = lforw(lp))
240: ntrd++;
241:
1.1 deraadt 242: lp = curwp->w_linep;
1.4 millert 243:
244: /* old is upper window */
245: if (ntrd <= ntru) {
246: /* hit mode line */
247: if (ntrd == ntru)
1.1 deraadt 248: lp = lforw(lp);
249: curwp->w_ntrows = ntru;
250: wp->w_wndp = curwp->w_wndp;
251: curwp->w_wndp = wp;
1.3 millert 252: wp->w_toprow = curwp->w_toprow + ntru + 1;
1.1 deraadt 253: wp->w_ntrows = ntrl;
1.4 millert 254: /* old is lower window */
255: } else {
1.1 deraadt 256: wp1 = NULL;
257: wp2 = wheadp;
258: while (wp2 != curwp) {
259: wp1 = wp2;
260: wp2 = wp2->w_wndp;
261: }
262: if (wp1 == NULL)
263: wheadp = wp;
264: else
265: wp1->w_wndp = wp;
1.3 millert 266: wp->w_wndp = curwp;
1.1 deraadt 267: wp->w_toprow = curwp->w_toprow;
268: wp->w_ntrows = ntru;
1.4 millert 269:
270: /* mode line */
271: ++ntru;
1.1 deraadt 272: curwp->w_toprow += ntru;
1.3 millert 273: curwp->w_ntrows = ntrl;
1.1 deraadt 274: while (ntru--)
275: lp = lforw(lp);
276: }
1.4 millert 277:
278: /* adjust the top lines if necessary */
279: curwp->w_linep = lp;
280: wp->w_linep = lp;
281:
1.26 kjell 282: curwp->w_rflag |= WFMODE | WFFULL;
283: wp->w_rflag |= WFMODE | WFFULL;
1.27 kjell 284: /* if FFOTHARG, set flags) */
285: if (f & FFOTHARG)
286: wp->w_flag = n;
287:
1.16 db 288: return (TRUE);
1.1 deraadt 289: }
290:
291: /*
1.7 mickey 292: * Enlarge the current window. Find the window that loses space. Make sure
293: * it is big enough. If so, hack the window descriptions, and ask redisplay
294: * to do all the hard work. You don't just set "force reframe" because dot
1.4 millert 295: * would move.
1.1 deraadt 296: */
1.3 millert 297: /* ARGSUSED */
1.4 millert 298: int
1.11 cloder 299: enlargewind(int f, int n)
1.1 deraadt 300: {
1.19 deraadt 301: struct mgwin *adjwp;
302: struct line *lp;
303: int i;
1.1 deraadt 304:
305: if (n < 0)
1.16 db 306: return (shrinkwind(f, -n));
1.1 deraadt 307: if (wheadp->w_wndp == NULL) {
1.30 ! lum 308: dobeep();
1.1 deraadt 309: ewprintf("Only one window");
1.16 db 310: return (FALSE);
1.1 deraadt 311: }
1.3 millert 312: if ((adjwp = curwp->w_wndp) == NULL) {
1.1 deraadt 313: adjwp = wheadp;
314: while (adjwp->w_wndp != curwp)
315: adjwp = adjwp->w_wndp;
316: }
317: if (adjwp->w_ntrows <= n) {
1.30 ! lum 318: dobeep();
1.1 deraadt 319: ewprintf("Impossible change");
1.16 db 320: return (FALSE);
1.1 deraadt 321: }
1.4 millert 322:
323: /* shrink below */
324: if (curwp->w_wndp == adjwp) {
1.1 deraadt 325: lp = adjwp->w_linep;
1.25 kjell 326: for (i = 0; i < n && lp != adjwp->w_bufp->b_headp; ++i)
1.1 deraadt 327: lp = lforw(lp);
1.3 millert 328: adjwp->w_linep = lp;
1.1 deraadt 329: adjwp->w_toprow += n;
1.4 millert 330: /* shrink above */
331: } else {
1.1 deraadt 332: lp = curwp->w_linep;
1.25 kjell 333: for (i = 0; i < n && lback(lp) != curbp->b_headp; ++i)
1.1 deraadt 334: lp = lback(lp);
1.3 millert 335: curwp->w_linep = lp;
1.1 deraadt 336: curwp->w_toprow -= n;
337: }
338: curwp->w_ntrows += n;
339: adjwp->w_ntrows -= n;
1.26 kjell 340: curwp->w_rflag |= WFMODE | WFFULL;
341: adjwp->w_rflag |= WFMODE | WFFULL;
1.16 db 342: return (TRUE);
1.1 deraadt 343: }
344:
345: /*
1.7 mickey 346: * Shrink the current window. Find the window that gains space. Hack at the
1.4 millert 347: * window descriptions. Ask the redisplay to do all the hard work.
1.1 deraadt 348: */
1.4 millert 349: int
1.11 cloder 350: shrinkwind(int f, int n)
1.1 deraadt 351: {
1.19 deraadt 352: struct mgwin *adjwp;
353: struct line *lp;
354: int i;
1.1 deraadt 355:
356: if (n < 0)
1.16 db 357: return (enlargewind(f, -n));
1.1 deraadt 358: if (wheadp->w_wndp == NULL) {
1.30 ! lum 359: dobeep();
1.1 deraadt 360: ewprintf("Only one window");
1.16 db 361: return (FALSE);
1.1 deraadt 362: }
363: /*
364: * Bit of flakiness - KRANDOM means it was an internal call, and
365: * to be trusted implicitly about sizes.
366: */
1.3 millert 367: if (!(f & FFRAND) && curwp->w_ntrows <= n) {
1.30 ! lum 368: dobeep();
1.1 deraadt 369: ewprintf("Impossible change");
370: return (FALSE);
371: }
1.3 millert 372: if ((adjwp = curwp->w_wndp) == NULL) {
1.1 deraadt 373: adjwp = wheadp;
374: while (adjwp->w_wndp != curwp)
375: adjwp = adjwp->w_wndp;
376: }
1.4 millert 377:
378: /* grow below */
379: if (curwp->w_wndp == adjwp) {
1.1 deraadt 380: lp = adjwp->w_linep;
1.25 kjell 381: for (i = 0; i < n && lback(lp) != adjwp->w_bufp->b_headp; ++i)
1.1 deraadt 382: lp = lback(lp);
1.3 millert 383: adjwp->w_linep = lp;
1.1 deraadt 384: adjwp->w_toprow -= n;
1.4 millert 385: /* grow above */
386: } else {
1.1 deraadt 387: lp = curwp->w_linep;
1.25 kjell 388: for (i = 0; i < n && lp != curbp->b_headp; ++i)
1.1 deraadt 389: lp = lforw(lp);
1.3 millert 390: curwp->w_linep = lp;
1.1 deraadt 391: curwp->w_toprow += n;
392: }
393: curwp->w_ntrows -= n;
394: adjwp->w_ntrows += n;
1.26 kjell 395: curwp->w_rflag |= WFMODE | WFFULL;
396: adjwp->w_rflag |= WFMODE | WFFULL;
1.1 deraadt 397: return (TRUE);
398: }
399:
400: /*
1.7 mickey 401: * Delete current window. Call shrink-window to do the screen updating, then
1.4 millert 402: * throw away the window.
1.1 deraadt 403: */
1.3 millert 404: /* ARGSUSED */
1.4 millert 405: int
1.11 cloder 406: delwind(int f, int n)
1.1 deraadt 407: {
1.19 deraadt 408: struct mgwin *wp, *nwp;
1.1 deraadt 409:
1.3 millert 410: wp = curwp; /* Cheap... */
1.4 millert 411:
1.1 deraadt 412: /* shrinkwind returning false means only one window... */
413: if (shrinkwind(FFRAND, wp->w_ntrows + 1) == FALSE)
1.16 db 414: return (FALSE);
1.1 deraadt 415: if (--wp->w_bufp->b_nwnd == 0) {
1.3 millert 416: wp->w_bufp->b_dotp = wp->w_dotp;
417: wp->w_bufp->b_doto = wp->w_doto;
1.1 deraadt 418: wp->w_bufp->b_markp = wp->w_markp;
419: wp->w_bufp->b_marko = wp->w_marko;
420: }
1.4 millert 421:
1.1 deraadt 422: /* since shrinkwind did't crap out, we know we have a second window */
1.3 millert 423: if (wp == wheadp)
424: wheadp = curwp = wp->w_wndp;
425: else if ((curwp = wp->w_wndp) == NULL)
426: curwp = wheadp;
1.1 deraadt 427: curbp = curwp->w_bufp;
428: for (nwp = wheadp; nwp != NULL; nwp = nwp->w_wndp)
429: if (nwp->w_wndp == wp) {
430: nwp->w_wndp = wp->w_wndp;
1.3 millert 431: break;
1.1 deraadt 432: }
1.18 kjell 433: free(wp);
1.16 db 434: return (TRUE);
1.1 deraadt 435: }