/* window.c -- inplements window.h */ #include "window.h" /* window.c * * Window management. Some of the functions are internal, and some are * attached to keys that the user actually types. * */ #include <stdio.h> #include "basic.h" #include "buffer.h" #include "display.h" #include "estruct.h" #include "execute.h" #include "line.h" #include "terminal.h" #include "wrapper.h" struct window *curwp ; /* Current window */ struct window *wheadp ; /* Head of list of windows */ static struct window *swindow = NULL ; /* saved window pointer */ /* * Reposition dot in the current window to line "n". If the argument is * positive, it is that line. If it is negative it is that line from the * bottom. If it is 0 the window is centered (this is what the standard * redisplay code does). With no argument it defaults to 0. Bound to M-!. */ int reposition(int f, int n) { if (f == FALSE) /* default to 0 to center screen */ n = 0; curwp->w_force = n; curwp->w_flag |= WFFORCE; return TRUE; } /* * Refresh the screen. With no argument, it just does the refresh. With an * argument it recenters "." in the current window. Bound to "C-L". */ int redraw(int f, int n) { if (f == FALSE) sgarbf = TRUE; else { curwp->w_force = 0; /* Center dot. */ curwp->w_flag |= WFFORCE; } return TRUE; } /* * The command make the next window (next => down the screen) the current * window. There are no real errors, although the command does nothing if * there is only 1 window on the screen. Bound to "C-X C-N". * * with an argument this command finds the <n>th window from the top * * int f, n; default flag and numeric argument * */ int nextwind(int f, int n) { struct window *wp; int nwindows; /* total number of windows */ if (f) { /* first count the # of windows */ wp = wheadp; nwindows = 1; while (wp->w_wndp != NULL) { nwindows++; wp = wp->w_wndp; } /* if the argument is negative, it is the nth window from the bottom of the screen */ if (n < 0) n = nwindows + n + 1; /* if an argument, give them that window from the top */ if (n > 0 && n <= nwindows) { wp = wheadp; while (--n) wp = wp->w_wndp; } else { mlwrite("Window number out of range"); return FALSE; } } else if ((wp = curwp->w_wndp) == NULL) wp = wheadp; curwp = wp; curbp = wp->w_bufp; cknewwindow(); upmode(); return TRUE; } /* * This command makes the previous window (previous => up the screen) the * current window. There arn't any errors, although the command does not do a * lot if there is 1 window. */ int prevwind(int f, int n) { struct window *wp1; struct window *wp2; /* if we have an argument, we mean the nth window from the bottom */ if (f) return nextwind(f, -n); wp1 = wheadp; wp2 = curwp; if (wp1 == wp2) wp2 = NULL; while (wp1->w_wndp != wp2) wp1 = wp1->w_wndp; curwp = wp1; curbp = wp1->w_bufp; cknewwindow(); upmode(); return TRUE; } /* * This command moves the current window down by "arg" lines. Recompute the * top line in the window. The move up and move down code is almost completely * the same; most of the work has to do with reframing the window, and picking * a new dot. We share the code by having "move down" just be an interface to * "move up". Magic. Bound to "C-X C-N". */ int mvdnwind(int f, int n) { return mvupwind(f, -n); } /* * Move the current window up by "arg" lines. Recompute the new top line of * the window. Look to see if "." is still on the screen. If it is, you win. * If it isn't, then move "." to center it in the new framing of the window * (this command does not really move "."; it moves the frame). Bound to * "C-X C-P". */ int mvupwind(int f, int n) { struct line *lp; int i; lp = curwp->w_linep; if (n < 0) { while (n++ && lp != curbp->b_linep) lp = lforw(lp); } else { while (n-- && lback(lp) != curbp->b_linep) lp = lback(lp); } curwp->w_linep = lp; curwp->w_flag |= WFHARD; /* Mode line is OK. */ for (i = 0; i < curwp->w_ntrows; ++i) { if (lp == curwp->w_dotp) return TRUE; if (lp == curbp->b_linep) break; lp = lforw(lp); } lp = curwp->w_linep; i = curwp->w_ntrows / 2; while (i-- && lp != curbp->b_linep) lp = lforw(lp); curwp->w_dotp = lp; curwp->w_doto = 0; return TRUE; } /* * This command makes the current window the only window on the screen. Bound * to "C-X 1". Try to set the framing so that "." does not have to move on the * display. Some care has to be taken to keep the values of dot and mark in * the buffer structures right if the distruction of a window makes a buffer * become undisplayed. */ int onlywind(int f, int n) { struct window *wp; struct line *lp; int i; while (wheadp != curwp) { wp = wheadp; wheadp = wp->w_wndp; if (--wp->w_bufp->b_nwnd == 0) { wp->w_bufp->b_dotp = wp->w_dotp; wp->w_bufp->b_doto = wp->w_doto; wp->w_bufp->b_markp = wp->w_markp; wp->w_bufp->b_marko = wp->w_marko; } free((char *) wp); } while (curwp->w_wndp != NULL) { wp = curwp->w_wndp; curwp->w_wndp = wp->w_wndp; if (--wp->w_bufp->b_nwnd == 0) { wp->w_bufp->b_dotp = wp->w_dotp; wp->w_bufp->b_doto = wp->w_doto; wp->w_bufp->b_markp = wp->w_markp; wp->w_bufp->b_marko = wp->w_marko; } free((char *) wp); } lp = curwp->w_linep; i = curwp->w_toprow; while (i != 0 && lback(lp) != curbp->b_linep) { --i; lp = lback(lp); } curwp->w_toprow = 0; curwp->w_ntrows = term.t_nrow - 1; curwp->w_linep = lp; curwp->w_flag |= WFMODE | WFHARD; return TRUE; } /* * Delete the current window, placing its space in the window above, * or, if it is the top window, the window below. Bound to C-X 0. * * int f, n; arguments are ignored for this command */ int delwind(int f, int n) { struct window *wp; /* window to recieve deleted space */ struct window *lwp; /* ptr window before curwp */ int target; /* target line to search for */ /* if there is only one window, don't delete it */ if (wheadp->w_wndp == NULL) { mlwrite("Can not delete this window"); return FALSE; } /* find window before curwp in linked list */ wp = wheadp; lwp = NULL; while (wp != NULL) { if (wp == curwp) break; lwp = wp; wp = wp->w_wndp; } /* find recieving window and give up our space */ wp = wheadp; if (curwp->w_toprow == 0) { /* find the next window down */ target = curwp->w_ntrows + 1; while (wp != NULL) { if (wp->w_toprow == target) break; wp = wp->w_wndp; } if (wp == NULL) return FALSE; wp->w_toprow = 0; wp->w_ntrows += target; } else { /* find the next window up */ target = curwp->w_toprow - 1; while (wp != NULL) { if ((wp->w_toprow + wp->w_ntrows) == target) break; wp = wp->w_wndp; } if (wp == NULL) return FALSE; wp->w_ntrows += 1 + curwp->w_ntrows; } /* get rid of the current window */ if (--curwp->w_bufp->b_nwnd == 0) { curwp->w_bufp->b_dotp = curwp->w_dotp; curwp->w_bufp->b_doto = curwp->w_doto; curwp->w_bufp->b_markp = curwp->w_markp; curwp->w_bufp->b_marko = curwp->w_marko; } if (lwp == NULL) wheadp = curwp->w_wndp; else lwp->w_wndp = curwp->w_wndp; free((char *) curwp); curwp = wp; wp->w_flag |= WFHARD; curbp = wp->w_bufp; cknewwindow(); upmode(); return TRUE; } /* * Split the current window. A window smaller than 3 lines cannot be * split. An argument of 1 forces the cursor into the upper window, an * argument of two forces the cursor to the lower window. The only * other error that is possible is a "malloc" failure allocating the * structure for the new window. Bound to "C-X 2". * * int f, n; default flag and numeric argument */ int splitwind(int f, int n) { struct window *wp; struct line *lp; int ntru; int ntrl; int ntrd; struct window *wp1; struct window *wp2; if (curwp->w_ntrows < 3) { mlwrite("Cannot split a %d line window", curwp->w_ntrows); return FALSE; } wp = xmalloc(sizeof(struct window)); ++curbp->b_nwnd; /* Displayed twice. */ wp->w_bufp = curbp; wp->w_dotp = curwp->w_dotp; wp->w_doto = curwp->w_doto; wp->w_markp = curwp->w_markp; wp->w_marko = curwp->w_marko; wp->w_flag = 0; wp->w_force = 0; #if COLOR /* set the colors of the new window */ wp->w_fcolor = gfcolor; wp->w_bcolor = gbcolor; #endif ntru = (curwp->w_ntrows - 1) / 2; /* Upper size */ ntrl = (curwp->w_ntrows - 1) - ntru; /* Lower size */ lp = curwp->w_linep; ntrd = 0; while (lp != curwp->w_dotp) { ++ntrd; lp = lforw(lp); } lp = curwp->w_linep; if (((f == FALSE) && (ntrd <= ntru)) || ((f == TRUE) && (n == 1))) { /* Old is upper window. */ if (ntrd == ntru) /* Hit mode line. */ lp = lforw(lp); curwp->w_ntrows = ntru; wp->w_wndp = curwp->w_wndp; curwp->w_wndp = wp; wp->w_toprow = curwp->w_toprow + ntru + 1; wp->w_ntrows = ntrl; } else { /* Old is lower window */ wp1 = NULL; wp2 = wheadp; while (wp2 != curwp) { wp1 = wp2; wp2 = wp2->w_wndp; } if (wp1 == NULL) wheadp = wp; else wp1->w_wndp = wp; wp->w_wndp = curwp; wp->w_toprow = curwp->w_toprow; wp->w_ntrows = ntru; ++ntru; /* Mode line. */ curwp->w_toprow += ntru; curwp->w_ntrows = ntrl; while (ntru--) lp = lforw(lp); } curwp->w_linep = lp; /* Adjust the top lines */ wp->w_linep = lp; /* if necessary. */ curwp->w_flag |= WFMODE | WFHARD; wp->w_flag |= WFMODE | WFHARD; return TRUE; } /* * Enlarge the current window. Find the window that loses space. Make sure it * is big enough. If so, hack the window descriptions, and ask redisplay to do * all the hard work. You don't just set "force reframe" because dot would * move. Bound to "C-X Z". */ int enlargewind(int f, int n) { struct window *adjwp; struct line *lp; int i; if (n < 0) return shrinkwind(f, -n); if (wheadp->w_wndp == NULL) { mlwrite("Only one window"); return FALSE; } if ((adjwp = curwp->w_wndp) == NULL) { adjwp = wheadp; while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp; } if (adjwp->w_ntrows <= n) { mlwrite("Impossible change"); return FALSE; } if (curwp->w_wndp == adjwp) { /* Shrink below. */ lp = adjwp->w_linep; for (i = 0; i < n && lp != adjwp->w_bufp->b_linep; ++i) lp = lforw(lp); adjwp->w_linep = lp; adjwp->w_toprow += n; } else { /* Shrink above. */ lp = curwp->w_linep; for (i = 0; i < n && lback(lp) != curbp->b_linep; ++i) lp = lback(lp); curwp->w_linep = lp; curwp->w_toprow -= n; } curwp->w_ntrows += n; adjwp->w_ntrows -= n; #if SCROLLCODE curwp->w_flag |= WFMODE | WFHARD | WFINS; adjwp->w_flag |= WFMODE | WFHARD | WFKILLS; #else curwp->w_flag |= WFMODE | WFHARD; adjwp->w_flag |= WFMODE | WFHARD; #endif return TRUE; } /* * Shrink the current window. Find the window that gains space. Hack at the * window descriptions. Ask the redisplay to do all the hard work. Bound to * "C-X C-Z". */ int shrinkwind(int f, int n) { struct window *adjwp; struct line *lp; int i; if (n < 0) return enlargewind(f, -n); if (wheadp->w_wndp == NULL) { mlwrite("Only one window"); return FALSE; } if ((adjwp = curwp->w_wndp) == NULL) { adjwp = wheadp; while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp; } if (curwp->w_ntrows <= n) { mlwrite("Impossible change"); return FALSE; } if (curwp->w_wndp == adjwp) { /* Grow below. */ lp = adjwp->w_linep; for (i = 0; i < n && lback(lp) != adjwp->w_bufp->b_linep; ++i) lp = lback(lp); adjwp->w_linep = lp; adjwp->w_toprow -= n; } else { /* Grow above. */ lp = curwp->w_linep; for (i = 0; i < n && lp != curbp->b_linep; ++i) lp = lforw(lp); curwp->w_linep = lp; curwp->w_toprow += n; } curwp->w_ntrows -= n; adjwp->w_ntrows += n; #if SCROLLCODE curwp->w_flag |= WFMODE | WFHARD | WFKILLS; adjwp->w_flag |= WFMODE | WFHARD | WFINS; #else curwp->w_flag |= WFMODE | WFHARD; adjwp->w_flag |= WFMODE | WFHARD; #endif return TRUE; } /* * Resize the current window to the requested size * * int f, n; default flag and numeric argument */ int resize(int f, int n) { int clines; /* current # of lines in window */ /* must have a non-default argument, else ignore call */ if (f == FALSE) return TRUE; /* find out what to do */ clines = curwp->w_ntrows; /* already the right size? */ if (clines == n) return TRUE; return enlargewind(TRUE, n - clines); } /* * Pick a window for a pop-up. Split the screen if there is only one window. * Pick the uppermost window that isn't the current window. An LRU algorithm * might be better. Return a pointer, or NULL on error. */ struct window *wpopup(void) { struct window *wp; if (wheadp->w_wndp == NULL /* Only 1 window */ && splitwind(FALSE, 0) == FALSE) /* and it won't split */ return NULL; wp = wheadp; /* Find window to use */ while (wp != NULL && wp == curwp) wp = wp->w_wndp; return wp; } int scrnextup(int f, int n) { /* scroll the next window up (back) a page */ nextwind(FALSE, 1); backpage(f, n); prevwind(FALSE, 1); return TRUE; } int scrnextdw(int f, int n) { /* scroll the next window down (forward) a page */ nextwind(FALSE, 1); forwpage(f, n); prevwind(FALSE, 1); return TRUE; } int savewnd(int f, int n) { /* save ptr to current window */ swindow = curwp; return TRUE; } int restwnd(int f, int n) { /* restore the saved screen */ struct window *wp; /* find the window */ wp = wheadp; while (wp != NULL) { if (wp == swindow) { curwp = wp; curbp = wp->w_bufp; upmode(); return TRUE; } wp = wp->w_wndp; } mlwrite("(No such window exists)"); return FALSE; } /* * resize the screen, re-writing the screen * * int f; default flag * int n; numeric argument */ int newsize(int f, int n) { struct window *wp; /* current window being examined */ struct window *nextwp; /* next window to scan */ struct window *lastwp; /* last window scanned */ int lastline; /* screen line of last line of current window */ /* if the command defaults, assume the largest */ if (f == FALSE) n = term.t_mrow + 1; /* make sure it's in range */ if (n < 3 || n > term.t_mrow + 1) { mlwrite("%%Screen size out of range"); return FALSE; } if (term.t_nrow == n - 1) return TRUE; else if (term.t_nrow < n - 1) { /* go to the last window */ wp = wheadp; while (wp->w_wndp != NULL) wp = wp->w_wndp; /* and enlarge it as needed */ wp->w_ntrows = n - wp->w_toprow - 2; wp->w_flag |= WFHARD | WFMODE; } else { /* rebuild the window structure */ nextwp = wheadp; wp = NULL; lastwp = NULL; while (nextwp != NULL) { wp = nextwp; nextwp = wp->w_wndp; /* get rid of it if it is too low */ if (wp->w_toprow > n - 2) { /* save the point/mark if needed */ if (--wp->w_bufp->b_nwnd == 0) { wp->w_bufp->b_dotp = wp->w_dotp; wp->w_bufp->b_doto = wp->w_doto; wp->w_bufp->b_markp = wp->w_markp; wp->w_bufp->b_marko = wp->w_marko; } /* update curwp and lastwp if needed */ if (wp == curwp) curwp = wheadp; curbp = curwp->w_bufp; if (lastwp != NULL) lastwp->w_wndp = NULL; /* free the structure */ free((char *) wp); wp = NULL; } else { /* need to change this window size? */ lastline = wp->w_toprow + wp->w_ntrows - 1; if (lastline >= n - 2) { wp->w_ntrows = n - wp->w_toprow - 2; wp->w_flag |= WFHARD | WFMODE; } } lastwp = wp; } } /* screen is garbage */ term.t_nrow = n - 1; sgarbf = TRUE; return TRUE; } /* * resize the screen, re-writing the screen * * int f; default flag * int n; numeric argument */ int newwidth(int f, int n) { struct window *wp; /* if the command defaults, assume the largest */ if (f == FALSE) n = term.t_mcol; /* make sure it's in range */ if (n < 10 || n > term.t_mcol) { mlwrite("%%Screen width out of range"); return FALSE; } /* otherwise, just re-width it (no big deal) */ term.t_ncol = n; term.t_margin = n / 10; term.t_scrsiz = n - (term.t_margin * 2); /* florce all windows to redraw */ wp = wheadp; while (wp) { wp->w_flag |= WFHARD | WFMOVE | WFMODE; wp = wp->w_wndp; } sgarbf = TRUE; return TRUE; } int getwpos(void) { /* get screen offset of current line in current window */ int sline; /* screen line from top of window */ struct line *lp; /* scannile line pointer */ /* search down the line we want */ lp = curwp->w_linep; sline = 1; while (lp != curwp->w_dotp) { ++sline; lp = lforw(lp); } /* and return the value */ return sline; } void cknewwindow(void) { execute(META | SPEC | 'X', FALSE, 1); }