2.9BSD/usr/contrib/jove/jove_wind.c

Compare this file to the similar file:
Show the results in this format:

/*
   Jonathan Payne at Lincoln-Sudbury Regional High School 5-25-83

   jove_wind.c

   This creates/deletes/divides/grows/shrinks windows.  */

#include "jove.h"
#include "termcap.h"

char	onlyone[] = "You only have one window, twit!";
char	toosmall[] = "too small";

/* First line in a window */

FLine(w)
WINDOW	*w;
{
	WINDOW	*wp = fwind;
	int	lineno = -1;

	do {
		if (wp == w)
			return lineno + 1;
		lineno += wp->w_height;
		wp = wp->w_next;
	} while (wp != fwind);
	complain("WINDOW?");
	/* NOTREACHED */
}

initwinds(b)
BUFFER	*b;
{
	WINDOW	*wp = fwind;

	do {
		if (wp->w_bufp == b) {
			SetTop(wp, (wp->w_line = b->b_dot));
			zero_wind(wp);
		}
		wp = wp->w_next;
	} while (wp != fwind);
}

/* Return last window on the screen */

WINDOW *
lastwind()
{
	WINDOW *wp = fwind;

	do {
		if (wp->w_next == fwind)
			return wp;
		wp = wp->w_next;
	} while (wp != fwind);
    /* NOTREACHED */
}

WINDOW *

getwind()
{
	WINDOW	*wp;
	
	wp = (WINDOW *)emalloc(sizeof (WINDOW));
	return wp;
}

/* Delete `wp' from the screen.  If it is the only window left
 * on the screen, then complain via error.  It gives its body
 * to the next window if there is one, otherwise the previous
 * window gets the body.  Resets link list and fwind if necessary.
 */

del_wind(wp)
WINDOW	*wp;
{
	WINDOW	*last = lastwind(),
		*prev = wp->w_prev;

	if (wp->w_next == wp)
		complain(onlyone);

	wp->w_prev->w_next = wp->w_next;
	wp->w_next->w_prev = wp->w_prev;
	
	if (fwind == wp) {
		fwind = wp->w_next;
		fwind->w_height += wp->w_height;
	} else if (wp == last)
		last->w_prev->w_height += wp->w_height;
	else
		prev->w_height += wp->w_height;
	if (curwind == wp)
		SetWind(prev);
	free((char *) wp);
}

/* Divide the `wp'.  Complains if `wp' is too small to be split.
 * It returns the new window
 */

WINDOW *
div_wind(wp)
WINDOW	*wp;
{
	WINDOW	*new;

	if (wp->w_height < 4)
		complain(toosmall);

	new = getwind();
	new->w_offset = 0;
	new->w_numlines = 0;
	/* Reset the window bounds */
	new->w_height = (wp->w_height / 2);
	wp->w_height -= new->w_height;

	/* Set the lines such that w_line is the center in each window */
	new->w_line = wp->w_line;
	new->w_bufp = wp->w_bufp;
	new->w_top = prev_line(new->w_line, HALF(new));

	/* Link the new window into the list */
	new->w_prev = wp;
	new->w_next = wp->w_next;
	new->w_next->w_prev = new;
	wp->w_next = new;
	return new;
}

/* Return one window previous to `wp'.  If at the first window
 * on screen, then go to the last window
 */

WINDOW *
prev_wind(wp)
WINDOW	*wp;
{
	return wp->w_prev;
}

/* Next window from `wp' */

WINDOW *
next_wind(wp)
WINDOW	*wp;
{
	return wp->w_next;
}

/* Initialze the first window setting the bounds to the size of the
 * screen.  There is no buffer with this window.  See parse for the
 * setting of this window.
 */

winit()
{
	curwind = fwind = getwind();

	curwind->w_line = curwind->w_top = (LINE *) 0;
	curwind->w_char = 0;
	curwind->w_next = curwind->w_prev = fwind;
	curwind->w_height = LI - 1;
}

/* Change window into the previous window.  curwind becomes the new
 * window
 */

PrevWindow()
{
	WINDOW	*new = prev_wind(curwind);

	if (new == curwind)
		complain(onlyone);
	SetWind(new);
}

/* Make new the current window */

SetWind(new)
WINDOW	*new;
{
	if (new == curwind)
		return;
	curwind->w_line = curline;
	curwind->w_char = curchar;
	curwind->w_bufp = curbuf;
	SetBuf(new->w_bufp);
	if (!inlist(new->w_bufp->b_zero, new->w_line)) {
		new->w_line = curline;
		new->w_char = curchar;
	}
	DotTo(new->w_line, new->w_char);
	if (curchar > strlen(linebuf))
		new->w_char = curchar = strlen(linebuf);
	curwind = new;
}

/* Delete the current window if it isn't the only one left */

DelCurWindow()
{
	del_wind(curwind);
}

/* Return the number of windows being displayed right now */

numwindows()
{
	WINDOW	*wp = fwind;
	int	num = 0;

	do {
		num++;
		wp = wp->w_next;
	} while (wp != fwind);
	return num;
}

WindFind()
{
	char	*fname = ask((char *) 0, FuncName());
	BUFFER	*buf;

	if (buf = file_exists(fname))
		pop_wind(buf->b_name, 0);
	else {
		if (numwindows() == 1)
			curwind = div_wind(curwind);
		else
			curwind = next_wind(curwind);
		SetBuf(do_find(curwind, fname));
	}
}

/* Go into one window mode by deleting all the other windows */

OneWindow()
{
	while (curwind->w_next != curwind)
		del_wind(curwind->w_next);
}

/* Look for a window containing a buffer whose name is `name' */

WINDOW *
windlook(name)
char	*name;
{
	BUFFER	*bp = (BUFFER *) buf_exists(name);
	WINDOW	*wp = fwind;

	if (bp == 0)
		return 0;
	do {
		if (wp->w_bufp == bp)
			return wp;
		wp = wp->w_next;
	} while (wp != fwind);
	return 0;
}

/* Change window into the next window.  curwind becomes the new
 * window
 */

NextWindow()
{
	WINDOW	*new = next_wind(curwind);

	if (new == curwind)
		complain(onlyone);
	SetWind(new);
}

/* Scroll the next window */

PageNWind()
{
	if (numwindows() == 1)
		complain(onlyone);
	NextWindow();
	NextPage();
	PrevWindow();
}

/* Put a window with the buffer `name' in it.  Erase the buffer if
 * `clobber' is non-zero.
 */

pop_wind(name, clobber)
char	*name;
{
	WINDOW	*wp;
	BUFFER	*newb;

	if ((wp = windlook(name)) == 0) {
		if (numwindows() == 1)
			SplitWind();
		else
			PrevWindow();
	} else
		SetWind(wp);

	newb = do_select((WINDOW *) 0, name);
	if (clobber)
		initlist(newb);
	tiewind(curwind, newb);
	SetBuf(newb);
}

GrowWindow()
{
	WindSize(curwind, abs(exp));
}

ShrWindow()
{
	WindSize(curwind, -abs(exp));
}

/* Change the size of the window by inc.  First arg is the window,
 * second is the increment.
 */

WindSize(w, inc)
register WINDOW	*w;
{
	if (numwindows() == 1)
		complain(onlyone);

	if (inc < 0) {	/* Shrinking this window */
		if (w->w_height + inc < 2)
			complain(toosmall);
		w->w_height += inc;
		w->w_prev->w_height -= inc;
	} else
		WindSize(w->w_next, -inc);
}

/* Set the topline of the window, calculating its number in the buffer.
 * This is for numbering the lines only.
 */

SetTop(w, line)
WINDOW	*w;
register LINE	*line;
{
	register LINE	*lp = w->w_bufp->b_zero;
	register int	num = 0;

	w->w_top = line;
	if (w->w_numlines)
		while (lp) {
			num++;
			if (line == lp)
				break;
			lp = lp->l_next;
		}
	w->w_topnum = num;
}

WNumLines()
{
	zero_wind(curwind);
	/* So the redisplay will know to update the screen even if it
	 * looks like there are no differences.
	 */

	curwind->w_numlines = !curwind->w_numlines;
	SetTop(curwind, curwind->w_top);
}

zero_wind(wp)
register WINDOW	*wp;
{
	register int	i,
			upper;

	upper = FLine(wp);
	for (i = 0; i < wp->w_height; i++)
		oimage[upper + i].Line = (LINE *) -1;
}

/* Return the line number that `line' occupies in `windes' */

in_window(windes, line)
register WINDOW	*windes;
register LINE	*line;
{
	register int	i;
	LINE	*top = windes->w_top;

	for (i = 0; top && i < windes->w_height - 1; i++, top = top->l_next)
		if (top == line)
			return FLine(windes) + i;
	return -1;
}