updated window manager - wm

sources-request at panda.UUCP sources-request at panda.UUCP
Fri Nov 15 11:53:36 AEST 1985


Mod.sources:  Volume 3, Issue 45
Submitted by: wjh12!pixel!pixutl!chris


Quite a while ago, Rob Jacob from NRL posted a window manager to the net.
It sat on my machine for a long time until I decided to play with it.
Eventually, I did. I enjoyed using it but I found some problems with it
and starting modifying it. Later someone else here got interested too
and we now have this version which we think is very nice. The list of
modifications is at the top of 'wm.c'. The compile options are described
in the makefile.

This version runs on our systems, which run a mostly 4.1 kernel. It compiled
on a 2.9 system, but ran very slowly. The main area that might cause problems
on non 68K systems is the code included by the 'FAST' #define. 'wm' runs a
lot faster if it is defined but that stuff is not necessarily portable (it
doesn't work on the PDP, for example).

Adapting it to 4.2 should require very little work and if someone does it and
enjoys 'wm', I would appreciate getting the changes back. I would also like
hearing about problems, bugs, improvements, etc...

The archive contains the following files:
	Makefile
	read.c
	win.c
	wm.1
	wm.c
	wm.h
This is a complete posting, not just the diff's because the changes are
everywhere and it was ran through 'cb' very early.

Warning: the format of the .wmrc file is different from that of the original
version, mostly because the control character is saved from one session to the
next so be sure to remove older .wmrc's or to used the '-' option on the first
run, if you plan on using it.

NOTE: This new version is posted with the authorization of the original author.

---------------------------- cut here -------------------------------
echo 'sh - Makefile'
sed 's/^X//' <<'________This_Is_The_END________' 			>>Makefile
X#
X# Note: Set NUMSUFFIX, PTYBASENAME, PTSBASENAME, PTFIRST, and PTLAST
X# in wm.h according to the instructions there before compiling
X#
X# If REVVIDEO is defined, the windows will handle reverse video.
X# If FAST is defined, some possibly non-portable routines will be used
X#    for string copy.
X# If SHOWMAP is defined, the 'M' command will display the window layout.
X# If SMOOTHIO is defined, programs that do a lot of cursor motions run
X#    smoother but hog system.
X#
X
XCFLAGS=-O -DREVVIDEO -DSHOWMAP -DFAST -DSMOOTHIO
XLDFLAGS=-n
XOBJS=wm.o read.o win.o
X
Xall: wm
X
Xwm: ${OBJS}
X	cc $(LDFLAGS) -o wm wm.o read.o win.o -lcurses -ltermcap
X
X${OBJS}: wm.h
X
Xinstall: all
X	install -s wm ${DESTDIR}/usr/local/bin
X
Xclean:
X	rm -f *.o wm core a.out mon.out
________This_Is_The_END________
echo 'sh - read.c'
sed 's/^X//' <<'________This_Is_The_END________' 			>>read.c
X/*
X * read.c  R. Jacob
X * This is the code that does all kinds of reading.
X *
X * Modified by Chris Bertin and Mike Tellier, October 1985.
X */
X
X#include <stdio.h>
X#include "wm.h" /* includes sgtty.h */
X#include <signal.h>
X
X/*
X * Old-fashioned blocking version of getchar
X * But uses unbuffered system call read
X * and strips parity bit
X */
Xbgetch(fildes)
Xint fildes; 
X{
X	char c;
X
X	if (read(fildes, &c, 1) <= 0)
X		return(EOF);
X	else
X		return((int)(c&0177));
X}
X
X/*
X * Returns the number of characters to be read.
X */
Xttychars(fildes)
Xint fildes; 
X{
X	long int count;
X
X	ioctl(fildes, FIONREAD, &count);
X	return(count);
X}
X
X/*
X * Key definitions used only by routine getpos
X * These keys are used only for entering position of new window
X */
X# define RIGHTCHAR	'r'
X# define UPCHAR		'u'
X# define LEFTCHAR	'l'
X# define DOWNCHAR	'd'
X# define BIGRIGHTCHAR	'R'	/* jump			*/
X# define BIGUPCHAR	'U'	/* one-fifth of the	*/
X# define BIGLEFTCHAR	'L'	/* way across		*/
X# define BIGDOWNCHAR	'D'	/* the screen		*/
X# define EXECCHAR	'x'
X
X/*
X * obtain a y, x position using UPCHAR, etc.
X * and return it as integers *yptr and *xptr
X * start off at position y0, x0
X * Does not permit bottom (y = LINES - 1) line, as it is saved for messages
X */
Xgetpos(yptr, xptr, y0, x0)
Xint *yptr, *xptr; 
Xregister int y0, x0; 
X{
X	register char c;
X	register int bigvert, bighoriz;
X	extern char cmdchar;
X
X	bigvert = LINES / 5 + 1;
X	bighoriz = COLS / 5 + 1;
X	showcursor(y0, x0);
X	while ((c = bgetch(0)) != EXECCHAR) {
X		if (c == RIGHTCHAR)
X			x0 = MIN(x0 + 1, COLS - 1);
X		else if (c == UPCHAR)
X			y0 = MAX(y0 - 1, 0);
X		else if (c == LEFTCHAR)
X			x0 = MAX(x0 - 1, 0);
X		else if (c == DOWNCHAR)
X			y0 = MIN(y0 + 1, LINES - 2);
X		else if (c == BIGRIGHTCHAR)
X			x0 = MIN(x0 + bighoriz, COLS - 1);
X		else if (c == BIGUPCHAR)
X			y0 = MAX(y0 - bigvert, 0);
X		else if (c == BIGLEFTCHAR)
X			x0 = MAX(x0 - bighoriz, 0);
X		else if (c == BIGDOWNCHAR)
X			y0 = MIN(y0 + bigvert, LINES - 2);
X		else if (c == cmdchar || c == 'q') {
X			showmsg("");
X			return(1);
X		}
X		showcursor(y0, x0);
X	}
X	*xptr = x0; 
X	*yptr = y0;
X	return(0);
X}
________This_Is_The_END________
echo 'sh - win.c'
sed 's/^X//' <<'________This_Is_The_END________' 			>>win.c
X/*
X * win.c  R. Jacob
X * This is the code for manipulating the window and curses data structures
X *
X * Modified by Chris Bertin and Mike Tellier, October 1985.
X */
X
X#include "wm.h"
X#include <ctype.h>
X
Xmap_t *winmap;
X
Xinit() {}
Xcloseup() {}
X
X/*
X * create byte-mapped top window image.
X */
Xmakemap()
X{
X	register struct win_struct *wsp;
X	register x, y, n, atlast;
X	register map_t *cp;
X	char c, lastc;
X
X#ifdef	FAST
X	zero(winmap, LINES * COLS * sizeof *winmap);
X#else
X	for (y = LINES * COLS; --y >= 0; )
X		winmap[y] = 0;
X#endif
X	for (wsp = topw->prev, atlast = 0; atlast == 0; wsp = wsp->prev) {
X		atlast = (wsp == topw);
X		if (wsp->flags & WERASED)
X			continue;
X		mapwindow(wsp->boxleft, wsp->id, 1);
X		mapwindow(wsp->boxright, wsp->id, 1);
X		mapwindow(wsp->boxtop, wsp->id, 0);
X		mapwindow(wsp->boxbot, wsp->id, 0);
X		mapwindow(wsp->wptr, wsp->id, 0);
X	}
X	for (y = LINES - 1; y >= 0; y--) {
X		cp = &winmap[y * COLS] + COLS - 1;
X		for (n = 0, lastc = 0, c = 0, x = 0; x < COLS; x++, cp--) {
X			if ((c = mapchar(*cp)) != 0
X#ifdef	FAST
X				&& (maptocount(*cp) == 0)
X#endif
X							   ) {
X				if (c != lastc) {
X					n = 0;
X					lastc = c;
X				}
X#ifdef	FAST
X				*cp = chartomap(c, ++n);
X#else
X				*cp = c;
X#endif
X			}
X		}
X	}
X}
X
X/*
X * Map window onto byte-mapped image
X */
Xmapwindow(wp, id, flag)
Xregister WINDOW *wp;
Xchar id;
X{
X	register x, y;
X	register map_t *cp;
X
X	if (wp == NULL)
X		return;
X	for (y = wp->_begy; y < wp->_maxy + wp->_begy; y++) {
X		cp = &winmap[y * COLS];
X		for (x = wp->_begx; x < wp->_maxx + wp->_begx; x++)
X#ifdef	FAST
X			cp[x] = chartomap(id, flag);
X#else
X			cp[x] = id;
X#endif
X	}
X}
X
X/*
X * make wsp the top window by changing topw and adjusting linked list
X */
Xchgwin(wsp)
Xregister struct win_struct *wsp;
X{
X	if (wsp == topw)
X		return;
X	wsp->flags &= ~WERASED;
X	wsp->flags |= WTOUCHED;
X	if (wsp->next) {
X		wsp->prev->next = wsp->next;
X		wsp->next->prev = wsp->prev;
X	}
X	if (topw) {
X		wsp->next = topw;
X		wsp->prev = topw->prev;
X		topw->prev = wsp;
X		wsp->prev->next = wsp;
X	}
X	else
X		wsp->next = wsp->prev = wsp;
X	topw = wsp;
X	makemap();
X}
X
X#define doscroll(w)	scrollok(w, TRUE), scroll(w), scrollok(w, FALSE), wmove(w, w->_maxy - 1, w->_curx)
X/*
X * Add character c to window wsp and to corresponding virtual window
X * and interpret virtual terminal commands
X */
Xadd(wsp, c)
Xstruct win_struct *wsp;
Xchar c;
X{
X	register WINDOW *wp, *vp;
X	register wpy, wpx, vpy, vpx;
X	int doit, moveit;
X
X	wp = wsp->wptr;
X	vp = wsp->virt;
X	getyx(wp, wpy, wpx);
X	getyx(vp, vpy, vpx);
X	doit = FALSE;
X	moveit = FALSE;
X
X	if (wsp->pend[0] == CODE && wsp->pend[1] == 'Y') { /* cursor motion */
X		if (wsp->pend[2] != '\0') { /* ESC-Y-pos */
X			wpy = vpy = (int)(wsp->pend[2] - ' ');
X			wpx = vpy = (int)(c - ' ');
X			moveit = TRUE;
X			wsp->pend[0] = '\0';
X		}
X		else {
X			wsp->pend[2] = c;
X			wsp->pend[3] = '\0';
X			return;
X		} /* ESC-Y */
X	}
X	else if (wsp->pend[0] == CODE) { /* ESC */
X#ifdef	SMOOTHIO
X		wsp->flags |= WTOUCHED;
X		repaint(wsp);
X#endif
X		if (c == 'Y') {
X			wsp->pend[1] = c;
X			wsp->pend[2] = '\0';
X		}
X		else if (c == 'K') {
X			wclrtoeol(wp);
X			wclrtoeol(vp);
X			wsp->pend[0] = '\0';
X		}
X		else if (c == 'S') {
X			werase(wp);
X			werase(vp);
X			wpx = vpx = 0;
X			wpy = vpy = 0;
X			moveit = TRUE;
X			wsp->pend[0] = '\0';
X		}
X		else if (c == 'C') {
X			wpx++;
X			vpx++;
X			moveit = TRUE;
X			wsp->pend[0] = '\0';
X		}
X		else if (c == 'A') {
X			wpy--;
X			vpy--;
X			moveit = TRUE;
X			wsp->pend[0] = '\0';
X		}
X#ifdef	REVVIDEO
X		else if (c == 'O') {
X			wstandout(wp);
X			wstandout(vp);
X			wsp->pend[0] = '\0';
X		}
X		else if (c == 'E') {
X			wstandend(wp);
X			wstandend(vp);
X			wsp->pend[0] = '\0';
X		}
X#endif
X		else {
X			doit = TRUE;
X			wsp->pend[0] = '\0';
X		}
X	}
X	else if (c == CODE) {
X		wsp->pend[0] = c;
X		wsp->pend[1] = '\0';
X	}
X	else
X		doit = TRUE;
X	if (moveit || !doit) {
X		if (wpx < 0)
X			wpx = 0;
X		else if (wpx >= wp->_maxx)
X			wpx = wp->_maxx - 1;
X		if (wpy < 0)
X			wpy = 0;
X		else if (wpy >= wp->_maxy)
X			wpy = wp->_maxy - 1;
X		wmove(wp, wpy, wpx);
X		if (vpx < 0)
X			vpx = 0;
X		else if (vpx >= vp->_maxx)
X			vpx = vp->_maxx - 1;
X		if (vpy < 0)
X			vpy = 0;
X		else if (vpy >= vp->_maxy)
X			vpy = vp->_maxy - 1;
X		wmove(vp, vpy, vpx);
X		return;
X	}
X	if (c == '\007') {
X		showmsg("        ");
X		showmsg("");
X		showmsg("Bell");
X		return;
X	}
X	else if (c == '\b') {
X		if (wp->_curx > 0)
X			wp->_curx--;
X		if (vp->_curx > 0)
X			vp->_curx--;
X	}
X	else if (c == '\r') {
X		wp->_curx = 0;
X		vp->_curx = 0;
X	}
X	else if (c == '\n') {
X		wp->_cury++;
X		if (wp->_cury >= wp->_maxy)
X			doscroll(wp);
X		vp->_cury++;
X		if (vp->_cury >= vp->_maxy)
X			doscroll(vp);
X		if (wsp == topw || wp->_cury == wp->_maxy - 1) {
X			wsp->flags |= WTOUCHED;
X			repaint(wsp);
X		}
X	}
X	else if (isprint(c) || c == ' ' || c == '\t') {
X		int corner = (wp->_curx == wp->_maxx - 1) &&
X			     (wp->_cury == wp->_maxy - 1);
X		waddch(wp, c);
X		waddch(vp, c);
X		if (corner) {
X			add(wsp, '\n');
X			wmove(wp, wp->_cury, 0);
X			wmove(vp, vp->_cury, 0);
X		}
X	}
X	else if (c != '\0') {
X		if (c < '\040')
X			c += 0100;
X		else if (c == '\177')
X			c = '?';
X		waddch(wp, '^');
X		waddch(vp, '^');
X		waddch(wp, c);
X		waddch(vp, c);
X	}
X}
X
X/*
X * Creates up to 4 windows making a box to surround window wsp and puts
X * pointer to the new windows into proper places in global win[].
X * Sets WFULLSCREEN if applicable.
X */
Xsetupbox(wsp)
Xstruct win_struct *wsp;
X{
X	WINDOW *wp;
X	int top, bot, left, right;
X	int begx, begy, maxx, maxy;
X	int i;
X
X	wp = wsp->wptr; /* just to save typing */
X	begx = wp->_begx;
X	begy = wp->_begy;
X	maxx = wp->_maxx;
X	maxy = wp->_maxy;
X	wsp->boxtop = wsp->boxleft = wsp->boxright = wsp->boxbot = 0;
X	left = (begx > 0)? TRUE: FALSE;
X	top = (begy > 0)? TRUE: FALSE;
X	right = (begx+maxx < COLS)? TRUE: FALSE;
X	bot = (begy+maxy < LINES - 1)? TRUE: FALSE;
X	if (top)
X		begy--, maxy++;
X	if (bot)
X		maxy++;
X	if (left)
X		begx--, maxx++;
X	if (right)
X		maxx++;
X	if (top) {
X		wsp->boxtop = newwin(1, maxx, begy, begx);
X		wsp->boxtop->_flags = 0; /* get around curses bug */
X		leaveok(wsp->boxtop, TRUE);
X		for (i = 0; i < maxx; i++)
X			waddch(wsp->boxtop, wsp->id);
X		begy++;
X		maxy--;
X	}
X	if (left) {
X		wsp->boxleft = newwin(maxy, 1, begy, begx);
X		wsp->boxleft->_flags = 0; /* get around curses bug */
X		leaveok(wsp->boxleft, TRUE);
X		for (i = 0; i < maxy - 1; i++)
X			waddch(wsp->boxleft, '|');
X		waddch(wsp->boxleft, wsp->id);
X		begx++;
X		maxx--;
X	}
X	if (right) {
X		wsp->boxright = newwin(maxy, 1, begy, maxx+begx - 1);
X		wsp->boxright->_flags = 0; /* get around curses bug */
X		leaveok(wsp->boxright, TRUE);
X		for (i = 0; i < maxy - 1; i++)
X			waddch(wsp->boxright, '|');
X		waddch(wsp->boxright, wsp->id);
X		maxx--;
X	}
X	if (bot) {
X		wsp->boxbot = newwin(1, maxx, maxy+begy - 1, begx);
X		wsp->boxbot->_flags = 0; /* get around curses bug */
X		leaveok(wsp->boxbot, TRUE);
X		for (i = 0; i < maxx; i++)
X			waddch(wsp->boxbot, '-');
X	}
X	if ((top | bot | right | left) == 0)
X		wsp->flags |= WFULLSCREEN;
X	else
X		wsp->flags &= ~WFULLSCREEN;
X}
X
X/*
X * Clear the screen and then repaint all windows
X */
Xrepaintall()
X{
X	register struct win_struct *wsp;
X	int atlast;
X
X	ttyclear();
X	makemap();
X	wsp = (topw->flags & WFULLSCREEN)? topw: topw->prev;
X	for (atlast = 0; atlast == 0; wsp = wsp->prev) {
X		atlast = (wsp == topw);
X		if (wsp->boxtop)
X			touchwin(wsp->boxtop);
X		if (wsp->boxbot)
X			touchwin(wsp->boxbot);
X		if (wsp->boxleft)
X			touchwin(wsp->boxleft);
X		if (wsp->boxright)
X			touchwin(wsp->boxright);
X		touchwin(wsp->wptr);
X		wsp->flags |= WTOUCHED;
X		repaint(wsp);
X	}
X}
X
X/*
X * Repaint window wsp
X */
Xrepaint(wsp)
Xregister struct win_struct *wsp;
X{
X	if ((wsp->flags & WERASED) || (wsp->flags & WTOUCHED) == 0 ||
X	    ((wsp != topw) && (topw->flags & WFULLSCREEN)))
X		return;
X	wcopy(wsp->boxleft, wsp->id);
X	wcopy(wsp->boxright, wsp->id);
X	wcopy(wsp->boxtop, wsp->id);
X	wcopy(wsp->boxbot, wsp->id);
X	wcopy(wsp->wptr, wsp->id);
X	wsp->flags &= ~WTOUCHED;
X	refresh();
X}
X
X/*
X * Copy window image into byte-mapped top window
X */
Xwcopy(win, id)
Xregister WINDOW *win;
Xregister char id;
X{
X	register char *screen;
X	register map_t *map;
X	register count, x, y, bx, by, my;
X
X	if (win == NULL)
X		return;
X	bx = win->_begx;
X	by = win->_begy;
X	my = win->_maxy;
X	for (y = 0; y < my; y++) {
X		if ((x = win->_firstch[y]) == _NOCHANGE)
X			continue;
X		screen = &stdscr->_y[y + by][x + bx];
X		map = &winmap[(y + by) * COLS + x + bx];
X		for (; x <= win->_lastch[y]; x++, screen++, map++) {
X			if (mapchar(*map) != id)
X				continue;
X			if (stdscr->_firstch[y + by] == _NOCHANGE) {
X				stdscr->_firstch[y + by] = x + bx;
X				stdscr->_lastch[y + by] = x + bx;
X			}
X			if (stdscr->_firstch[y + by] > x + bx)
X				stdscr->_firstch[y + by] = x + bx;
X#ifdef	FAST
X			if ((count = maptocount(*map)) > 1) {
X				bcopy(&win->_y[y][x], screen, count);
X				x += count - 1;
X				screen += count - 1;
X				map += count - 1;
X			} else
X#endif
X				*screen = win->_y[y][x];
X			if (stdscr->_lastch[y + by] < x + bx)
X				stdscr->_lastch[y + by] = x + bx;
X		}
X	}
X}
X
X/*
X * show message at bottom of screen
X */
Xshowmsg(s)
Xchar *s; 
X{
X	extern msg;
X	int l = strlen(s);
X	extern WINDOW *msgwin;
X
X	wclear(msgwin);
X	wmove(msgwin, 0, 0);
X	wstandout(msgwin);
X	wprintw(msgwin, "%s", s);
X	overwrite(msgwin, stdscr);
X	refresh();
X	showcursor(msgwin->_begy, msgwin->_begx + l + 1);
X	msg = l > 0;
X}
X
X#ifdef	FAST
X/*
X * copy 'count' bytes from 'from' to 'to'. (optimized)
X */
Xbcopy(from, to, count)
Xregister char *from, *to;
Xregister count;
X{
X	register c1;
X
X	if ((((int)to ^ (int)from) & 1) == 0) {
X		if ((int)to & 1) {
X			count--;
X			*to++ = *from++;
X		}
X		c1 = count >> 2;
X		while (--c1 >= 0)
X			*(long *) to++ = *(long *) from++;
X		count &= 3;
X	}
X	while (--count >= 0)
X		*to++ = *from++;
X}
X
X/*
X * zero 'count' bytes in 'str'. (optimized)
X */
Xzero(str, count)
Xregister char *str;
Xregister count;
X{
X	register c1;
X
X	if ((int)str & 1) {
X		count--;
X		*str++ = 0;
X	}
X	c1 = count >> 2;
X	while (--c1 >= 0)
X		*(long *) str++ = 0L;
X	count &= 3;
X	while (--count >= 0)
X		*str++ = 0;
X}
X#endif
________This_Is_The_END________
echo 'sh - wm.1'
sed 's/^X//' <<'________This_Is_The_END________' 			>>wm.1
X.TH WM 1 wm.v42.1
X.SH NAME
Xwm \- window manager
X.SH SYNOPSIS
X.B wm
X[ \- ]
X.SH DESCRIPTION
X.I Wm
Xmanages a collection of windows on a display terminal.
X.PP
XIt determines what type of terminal you are using from
Xthe environment parameter $TERM
X(see
X.IR environ (5))
Xand then uses
X.IR curses (3)
Xto adapt to it.
X.PP
XEach window has its own UNIX shell
X.IR sh (1),
Xrunning in parallel with those in the other windows.
XThe idea behind this scheme is that you can use each window
Xfor a series of commands dealing with a single topic.
XThen, you can change back and forth between the windows without
Xlosing your place in any of them.
X.PP
XAt any time, you can give commands to change the window you are typing in,
Xto move a window or change its size,
Xor to create or kill a window.
XWindows can overlap or completely obscure one another;
Xobscured windows can subsequently be "lifted" up
Xand placed on top of the other windows.
X.PP
XWhen the program is started,
Xit will attempt to restore the sizes and positions of the windows
Xand the control character
Xin use when you last ran
X.IR wm .
XFailing that (or if you give the optional argument \- ),
Xit will ask you to indicate
Xthe size and position of the first window.
XTo do this, move the cursor to the position you want the
Xlower left corner of your window
Xto occupy,
Xusing the keys
X.B u
X(up),
X.B d
X(down),
X.B l
X(left), and
X.B r
X(right)
Xand also
X.BR U ,
X.BR D ,
X.BR L ,
Xand
X.B R
X(for large increments in the respective directions).
XThen type an
X.BR x .
XThen move the cursor (using the same commands) to the upper
Xright corner, and type another
X.BR x .
XNow, you can type UNIX commands in the new window.
X.PP
X.I Wm
Xcommands can be issued at any time.
XEvery
X.I wm
Xcommand consists of a prefix character followed by one
Xmore character, possibly followed by some arguments.
XAny other characters typed on the terminal are treated as input
Xto the program in the current window.
XTo enter the prefix character itself as input to a program, type it twice.
XThe prefix character is initially set to ASCII ESC, but can be changed
Xwith the
X.I C
Xcommand.  All commands can be interrupted by typing another prefix
Xcharacter or a
X.I q .
X.PP
XThe available
X.I wm
Xcommands are prefix character (ESC) followed by:
X.IP \fBn\fP
XCreate a new window.
X.I Wm
Xwill ask for the lower left and upper right corners,
Xusing the same convention described above for creating the first window.
X.IP \fBc\fP
XChange the current window.
XEnter the name (lower-case
X.BR a ,
X.BR b ,
X.BR c ,
Xetc.) of the
Xwindow to which you want to change.
XThe window names are shown in the top row of each window.
XThe chosen window is placed on "top" of the screen
X(that is, in front any other windows had been obscuring it).
XInput from the keyboard will now be sent to this window.
X(Delayed responses to commands entered in other windows will,
Xof course, continue to be routed to their correct windows.)
X.IP \fBl\fP
XChange to the last-used window.
XChange back to the window that had most recently been the current window.
X.IP \fBm\fP
XMove and/or change the size of a window.
X.I Wm
Xasks for the window name (same convention as for changing current window)
Xand then for the lower left and upper right corners of desired
Xnew position of the window (same convention as for the first window).
XIf you enlarge a window, material that had scrolled off the top or been
Xtruncated at the right margin will become visible again.
XIt is not advisable to move a window except when
Xthe program running in it is at the shell prompt level.
X.IP \fBe\fP
XErase the named window from the screen.
XThe window still exists, any pending processing continues in it
Xinvisibly, and it can be seen again with the change window command.
X.IP \fBk\fP
XKill the named window.
XPermanently kills the processes associated with the window
Xand erases the window.
X(The
X.I name
Xof this window may later be re-used in creating a new window.)
X.IP \fBC\fP
XChange the prefix character.
X.IP \fBr\fP
XRedraw the screen.
XClears the entire screen and redraws what should be there.
XHelpful after garbage (like a broadcast message) has arrived.
X.IP \fBp\fP
XScroll to the top of a new page in the current window.
XMaterial in a window is normally scrolled, one line at a time.
XThis command forces the window to scroll forward by a distance equal
Xto the height of the window, thereby clearing the window.
X.IP "\fBq\fP or \fBQ\fP"
XQuit.
XThis stops all processes associated with
X.I wm
Xand exits. If
X.I Q
Xis used, the
X.I .wmrc
Xfile is not updated.
X.IP \fBz\fP
XSuspend
X.I wm
Xusing the Berkeley job control system.
XThis should only be done if
X.I wm
Xitself was run from a shell that handles job control, i.e. from
X.IR csh (1),
Xrather than from the standard
X.IR sh (1).
X.IP \fBL\fP
XList the windows. The level (top first), name, shell's pid, virtual
Xdevice, coordinates, lines, columns and state are displayed.
X.IP \fBM\fP
XDisplay the map.
X.IP "\fBh\fP or \fB?\fP"
XHelp.
XDisplays a summary of
X.I wm
Xcommands.
X.PP
XIt is also possible to send data from one window to another.
XEach window is associated with the file name
X.B Window?
Xin the directory from which
X.I wm
Xwas run
X(where the
X.B ?
Xis replaced by
X.BR a ,
X.BR b ,
X.BR c ,
Xetc. for the particular windows).
XData sent to those file names will appear in the respective
Xwindows, and data read from those file names will be taken from
Xsubsequent keyboard input to those windows.
X(If real files by those names already exist, this feature will
Xbe disabled.)\ 
X.SH FILES
X.IP $HOME/.wmrc 20
Xis used to save the arrangement of your
Xwindows from one run to the next.
X.IP /dev/vt[sc]? 20
Xare the virtual terminals.
X.SH BUGS
XSome programs assume that their output devices are at
Xleast some minimum size;
Xthey will not run well in small windows.
XAlso, programs that attempt to manipulate the controlling
Xterminals of process groups will not work properly under
X.IR wm .
XFor this reason,
X.IR csh (1)
Xcannot be run in the individual windows instead of
X.IR sh (1).
X.PP
XEach window emulates a cursor-control terminal,
Xbut the emulation is provided largely by
X.IR curses ,
Xand it does not always do the same thing that a real terminal
Xwould do or that a program expects.
X.PP
XBecause of a deficiency in the virtual terminal driver in
Xhandling interrupt characters, the
X.I interrupt
Xand
X.I quit
Xkeyboard characters always send their
Xrespective signals to the program in the current window,
Xregardless of whether that program changed the definitions of
Xthe keys or not.
XThus, the program cannot re-map the keys,
Xeven if it has set raw mode,
Xbut it can still catch the signal
Xitself (as is usually done), rather than the character.
X.PP
XPrograms that do a lot of character I/O have make every other
Xwindow run slow.
X.SH "SEE ALSO"
XR.J.K. Jacob,
X"User-Level Window Managers for UNIX,"
X.I "Proc. UniForum International Conference on UNIX"
X(January, 1984).
X.SH AUTHORS
XRobert J.K. Jacob, Naval Research Laboratory
X.br
XChris Bertin and Mike Tellier, Pixel Systems Inc.
________This_Is_The_END________
echo 'sh - wm.c'
sed 's/^X//' <<'________This_Is_The_END________' 			>>wm.c
X/*
X * wm.c  R. Jacob  7/28/1980
X * Simple multiple-window monitor for Unix -- allows windows to overlap
X *
X * This is the code for the main program.
X * This version runs as only one process (plus the shells)
X * This is intended for Berkeley Unix with virtual tty's only.
X *
X * Modified by Chris Bertin and Mike Tellier, October 1985.
X * Major changes:
X *	- Use a byte-mapped screen image to keep track of which portions
X *	  of the windows should be displayed. This eliminates the jumping
X *	  from one window to another when updating hidden portions.
X *	- Read's from virtual tty's are now buffered. This assumes that
X *	  your kernel has 'FIONREAD' fixed for virtual tty's.
X *	- Window structures are now a doubly linked list for quicker scans.
X *	- Improved handling of the message window.
X *	- Reverse video handled in windows.
X *	- Improved user interface (Command are now interruptible by a 'q'
X *	  or by typing another command character, for example).
X *	- Lines wrap around inside the windows which means you always get
X *	  the full output.
X *	- VI's behaviour improved inside windows.
X *	- The command character can be passed to the window's process by
X *	  typing it twice.
X *	- The command character is saved from in the .wmrc file.
X *	- New commands: 'Q', 'L' and 'M'. See #define's below or manual.
X *	- WMRC now an environment variable.
X */
X
X#include <signal.h>
X#include <stdio.h>
X#include <curses.h>
X#include <ctype.h>
X#include "wm.h"
X
X/*
X * Command definitions
X */
X# define NEWWINDOW	'n'	/* make New window */
X# define CHGWINDOW	'c'	/* Change to another window */
X# define LASTWINDOW	'l'	/* change to Last-used window */
X# define PAGE		'p'	/* Page (vs scroll) the window */
X# define MOVEWINDOW	'm'	/* Move locn and/or change size of window */
X# define ERASEWINDOW	'e'	/* but it can reappear */
X# define KILLWINDOW	'k'	/* get rid of this window forever */
X# define REDRAW		'r'	/* Redraw all windows */
X# define HELP1		'?'	/* Command summary */
X# define HELP2		'h'	/* Command summary */
X# define SUSPEND	'z'	/* suspend wm */
X# define QUIT		'q'	/* close up everything and Quit */
X# define EXIT		'Q'	/* QUIT but exit without updating .wmrc */
X# define CHGCODE	'C'	/* change command character */
X# define LIST		'L'	/* list windows */
X# ifdef	 SHOWMAP
X# define MAP		'M'	/* display map */
X# endif
X
X# define DEFCMD		'\033'	/* default control character */
X# define INCR		500
X# define NOWIN		(struct win_struct *)0
X# define RDBSIZE	128
X# define pause()	showmsg("Hit any character to return to WM"),bgetch(0);
X# define interrupt(sig)	ioctl(topw->pty, TIOCFLUSH, 0), killpg(topw->pid, sig)
X# define setalarm()	rcount = 1, signal(SIGALRM, gotalarm), alarm(1)
X# define freespace(wsp)	{ if (wsp->buf) free(wsp->buf); free(wsp); }
X
Xchar cmdchar = DEFCMD;
X
X/*
X * Real declarations for stuff defined as extern in wm.h
X */
Xstruct win_struct *topw, *askwpnt(), *getwpnt();
X
Xchar *ptslinkname();
XWINDOW *msgwin;
X
Xchar shellpgm[100], shellname[20], wmrc[100];
Xstruct sgttyb sgttybuf;
Xstruct tchars tcharsbuf;
Xstruct ltchars ltcharsbuf;
Xint ttymode, ttydisc, timetoquit, nowmrc, rcount, msg;
X
Xgotalarm()
X{ 
X	signal(SIGALRM, gotalarm); 
X	rcount = 0;
X}
X
Xmain(argc)
Xint argc;
X{
X	register int alive, atlast, count, x, y;
X	register struct win_struct *wsp;
X	register char *pnt;
X	register WINDOW *wp;
X	FILE *file;
X	char intrc, quitc, c, buf[LINEBUF], *cp;
X	struct sw_buf savewin;
X
X	init();
X#ifdef	CSHWORKS /* for now force user to use sh cause csh doesn't work */
X	if ((cp = getenv("SHELL")) == (char *)0)
X		strcpy(shellpgm, "sh");
X	else
X		strcpy(shellpgm, cp);
X	if ((cp = rindex(shellpgm,'/')) == (char *)0)
X		strcpy(shellname, shellpgm);
X	else
X		strcpy(shellname, &cp[1]);
X#else
X	strcpy(shellpgm, "sh");
X	strcpy(shellname, "sh");
X#endif
X	ioctl(0, TIOCGETD, &ttydisc);
X	gtty(0, &sgttybuf);
X	ioctl(0, TIOCGETC, &tcharsbuf);
X	ioctl(0, TIOCLGET, &ttymode);
X	ioctl(0, TIOCGLTC, &ltcharsbuf);
X	intrc = tcharsbuf.t_intrc;
X	quitc = tcharsbuf.t_quitc;
X	initscr();
X	if ((winmap = (map_t *)malloc(LINES * COLS * sizeof (map_t))) == NULL) {
X		fprintf(stderr, "Can't allocate memory\n");
X		endwin();
X		exit(2);
X	}
X	noecho();
X	raw();
X	msgwin = newwin(1, 0, LINES - 1, 0);
X	msgwin->_flags = 0; /* to get around bug in curses */
X	firstwindow(argc);
X	strcpy(buf, "Ready");
X	if (cmdchar != DEFCMD)
X		sprintf(&buf[strlen(buf)], " (command character is '\\%04o')",
X			cmdchar);
X	showmsg(buf);
X	timetoquit = FALSE;
X	alive = INCR;
X	while (!timetoquit) {
X		for (atlast = 0, wsp = topw; atlast == 0; wsp = wsp->next) {
X			while (ttychars(0)) {
X				alive = INCR;
X				setalarm();
X				c = bgetch(0);
X				alarm(0);
X				if (rcount == 0 || c <= 0)
X					break;
X				if (c == cmdchar && docmd() != cmdchar)
X					break;
X				if (msg-- == 1)
X					showmsg("");
X				/*
X				 * We fake quit and interrupt here, since just
X				 * sending the characters on the pty doesn't do.
X				 * But don't change your intr or quit chars
X				 * inside a window!
X				 */
X				if (c == intrc)
X					interrupt(SIGINT);
X				else if (c == quitc)
X					interrupt(SIGQUIT);
X				else
X					write(topw->pty, &c, 1);
X			}
X			atlast = (wsp->next == topw);
X			if ((count = ttychars(wsp->pty)) == 0)
X				continue;
X			setalarm();
X			rcount = read(wsp->pty, wsp->buf, MIN(count, RDBSIZE));
X			alarm(0);
X			if (rcount <= 0)
X				continue;
X			wsp->flags |= WTOUCHED;
X			pnt = wsp->buf;
X			while(rcount-- > 0)
X				add(wsp, *pnt++);
X			alive = INCR * 2;
X			if (wsp != topw)
X				repaint(wsp);
X			topw->flags |= WTOUCHED;
X		}
X		if (topw->flags & WTOUCHED)
X			repaint(topw);
X		getyx(topw->wptr, y, x);
X		showcursor(y + topw->wptr->_begy, x + topw->wptr->_begx);
X		if (alive-- < 0)
X			sleep(1);
X	}
X	showmsg("");
X	showcursor(LINES - 1, 0);
X	if (!nowmrc && (file = fopen(wmrc, "w")) != NULL) {
X		for (atlast=0, wsp = topw->prev; atlast == 0; wsp = wsp->prev) {
X			atlast = (wsp == topw);
X			wp = wsp->wptr;
X			savewin.sw_begline = wp->_begy;
X			savewin.sw_begcol = wp->_begx;
X			savewin.sw_lines = wp->_maxy;
X			savewin.sw_cols = wp->_maxx;
X			savewin.sw_cmdchar = cmdchar;
X			fwrite(&savewin, sizeof(savewin), 1, file);
X		}
X	}
X	for (atlast = 0, wsp = topw; atlast == 0; wsp = wsp->next) {
X		atlast = (wsp->next == topw);
X		close(wsp->pty);
X		if (wsp->flags & WPTSLINK)
X			unlink(ptslinkname(wsp->id));
X		if (wsp->pid != 0) {
X			killpg(wsp->pid, SIGHUP);
X			kill(wsp->pid, SIGTERM);
X		}
X	}
X	closeup();
X	endwin();
X}
X
X/*
X * docmd() handles commands and returns the character it reads so that
X * the control character can be passed on to the windows.
X */
Xdocmd()
X{
X	register struct win_struct *wsp;
X	register char c;
X	char buf[LINEBUF];
X	int begline, begcol, lines, cols, savey, savex, y, x, x1, y1, x2, y2;
X	register l, lmax;
X
X	showmsg("Command?");
X	c = bgetch(0);
X	showmsg("");
X	switch(c) {
X
X	case NEWWINDOW:
X		showmsg("Move to lower left, then type x");
X		if (getpos(&y1, &x1, LINES-2, 0))
X			break;
X		showmsg("Move to upper right, then type x");
X		if (getpos(&y2, &x2, y1, x1))
X			break;
X		begline = y2;
X		begcol = x1;
X		lines = y1 - y2 + 1;
X		cols = x2 - x1 + 1;
X		if (lines > 0 && cols > 0) {
X			if (makewin(lines, cols, begline, begcol)) {
X				repaintall();
X				showmsg("Created new window");
X			}
X			else
X				showmsg("Can't create another shell");
X		}
X		else
X			showmsg("That's an impossible window size");
X		break;
X
X	case CHGWINDOW:
X		if ((wsp = askwpnt("Change to", 0)) == NOWIN || wsp == topw)
X			break;
X		chgwin(wsp);
X		repaintall();
X		showmsg("Changing windows");
X		break;
X
X	case LASTWINDOW:
X		if ((wsp = topw->next) == topw)
X			showmsg("No last window");
X		else {
X			chgwin(wsp);
X			repaintall();
X			showmsg("Changing windows");
X		}
X		break;
X
X	case PAGE:
X		showmsg("Page");
X		getyx(topw->wptr, savey, savex);
X		lmax = savey;
X		wmove(topw->wptr, 0, 0);
X		for (l = 0; l < lmax; l++)
X			wdeleteln(topw->wptr);
X		wmove(topw->wptr, savey - lmax, savex);
X		getyx(topw->virt, savey, savex);
X		wmove(topw->virt, 0, 0);
X		for (l = 0; l < lmax; l++)
X			wdeleteln(topw->virt);
X		wmove(topw->virt, savey - lmax, savex);
X		topw->flags |= WTOUCHED;
X		repaint(topw);
X		break;
X
X	case MOVEWINDOW:
X		if ((wsp = askwpnt("Move", 1)) == NOWIN)
X			break;
X		showmsg("Move to new lower left, then type x");
X		if (getpos(&y1, &x1, LINES-2, 0))
X			break;
X		showmsg("Move to new upper right, then type x");
X		if (getpos(&y2, &x2, y1, x1))
X			break;
X		begline = y2;
X		begcol = x1;
X		lines = y1 - y2 + 1;
X		cols = x2 - x1 + 1;
X		if (lines > 0 && cols > 0) {
X			int haslink = wsp->flags & WPTSLINK;
X			getyx(wsp->wptr, savey, savex);
X			savey = wsp->wptr->_maxy - savey;
X			delwin(wsp->wptr);
X			if (wsp->boxbot != 0)
X				delwin(wsp->boxbot);
X			if (wsp->boxtop != 0)
X				delwin(wsp->boxtop);
X			if (wsp->boxleft != 0)
X				delwin(wsp->boxleft);
X			if (wsp->boxright != 0)
X				delwin(wsp->boxright);
X			wsp->wptr = newwin(lines, cols, begline, begcol);
X			wsp->wptr->_flags = 0; /* get around curses bug */
X			for (y = 0; y < wsp->wptr->_maxy; y++) {
X				for (x = 0; x < wsp->wptr->_maxx; x++){
X					wmove(wsp->wptr, y, x);
X					wmove(wsp->virt, y + wsp->virt->_maxy - wsp->wptr->_maxy, x);
X					waddch(wsp->wptr, winch(wsp->virt));
X				}
X			}
X			if (haslink)
X				wsp->flags |= WPTSLINK;
X			wmove(wsp->virt, MAX(wsp->virt->_maxy - savey, 0),
X				savex);
X			wmove(wsp->wptr, MAX(wsp->wptr->_maxy - savey, 0),
X				savex);
X			ttyclear();
X			setupbox(wsp);
X			setenv(wsp);
X			makemap();
X			repaintall();
X			showmsg("Moving the window");
X		}
X		else
X			showmsg("That's an impossible window size");
X		break;
X
X	case ERASEWINDOW:
X		if ((wsp = askwpnt("Erase", 0)) == NOWIN)
X			break;
X		if (wsp == topw)
X			showmsg("Can't erase the top window");
X		else {
X			wsp->flags |= WERASED;
X			ttyclear();
X			repaintall();
X			showmsg("Erasing");
X		}
X		break;
X
X	case KILLWINDOW:
X		if ((wsp = askwpnt("Kill", 0)) == NOWIN)
X			break;
X		if (wsp == topw)
X			showmsg("Can't kill the top window");
X		else {
X			delwin(wsp->wptr);
X			delwin(wsp->virt);
X			if (wsp->boxbot != 0)
X				delwin(wsp->boxbot);
X			if (wsp->boxtop != 0)
X				delwin(wsp->boxtop);
X			if (wsp->boxleft != 0)
X				delwin(wsp->boxleft);
X			if (wsp->boxright != 0)
X				delwin(wsp->boxright);
X			if (wsp->flags & WPTSLINK)
X				unlink(ptslinkname(wsp->id));
X			close(wsp->pty);
X			if (wsp->pid != 0) {
X				killpg(wsp->pid, SIGHUP);
X				kill(wsp->pid, SIGKILL);
X			}
X			wsp->prev->next = wsp->next;
X			wsp->next->prev = wsp->prev;
X			freespace(wsp);
X			makemap();
X			ttyclear();
X			repaintall();
X			showmsg("Killing the window");
X		}
X		break;
X
X	case REDRAW:
X		repaintall();
X		showmsg("Redrawing");
X		break;
X
X	case LIST:
X		ttyclear();
X		refresh();
X		showwindows();
X		pause();
X		repaintall();
X		break;
X
X	case HELP1:
X	case HELP2:
X		ttyclear();
X		refresh();
X		helpmsg();
X		pause();
X		repaintall();
X		break;
X
X#ifdef	SHOWMAP
X	case MAP:
X		ttyclear();
X		for (x = 0; x < COLS; x++)
X		for (y = 0; y < LINES; y++)
X		    if (winmap[y * COLS + x])
X			mvwaddch(stdscr, y, x, mapchar(winmap[y * COLS + x]));
X		refresh();
X		pause();
X		repaintall();
X		break;
X#endif
X
X	case CHGCODE: /* change cmdchar */
X		showmsg("Enter new command character");
X		cmdchar = bgetch(0);
X		sprintf(buf, "New command character is '\\%04o'", cmdchar);
X		showmsg(buf);
X		break;
X
X#ifdef	SIGTSTP
X	case SUSPEND: /* Berkeley suspend job */
X		showmsg("Suspending");
X		kill(0, SIGTSTP);
X		showmsg("Resuming"); /* resume here */
X		break;
X#endif
X
X	case EXIT:
X		nowmrc++;
X	case QUIT: /* quit */
X		timetoquit = TRUE;
X		break;
X	default:
X		if (c != cmdchar) /* bad command */
X			showmsg("No such command -- use 'h' command for help");
X	}
X	return(c);
X}
X
X/*
X * Read in the file in $HOME/.wmrc if possible
X * Otherwise prompt for the first window
X */
Xfirstwindow(argc)
Xint argc;
X{
X	struct sw_buf savewin;
X	FILE *file;
X	int okflg;
X	int x1, y1, x2, y2;
X	int begline, begcol, cols, lines;
X	char *cp;
X
X	if ((cp = getenv("WMRC")) != (char *)0)
X		strcpy(wmrc, cp);
X	else {
X		if ((cp = getenv("HOME")) == (char *)0)
X			cp = ".";
X		sprintf(wmrc, "%s/.wmrc", cp);
X	}
X	if ((file = fopen(wmrc, "r")) != NULL && argc == 1) {
X		int reads = 0;
X		okflg = FALSE;
X		while (fread(&savewin, sizeof(savewin), 1, file) == 1) {
X			reads++;
X			if ((cmdchar = savewin.sw_cmdchar) == 0)
X				cmdchar = DEFCMD;
X			if (makewin(savewin.sw_lines, savewin.sw_cols,
X			   savewin.sw_begline, savewin.sw_begcol))
X				okflg = TRUE;
X			else {
X				if (! okflg) {
X					showmsg("Can't create any shells--sorry");
X					closeup();
X					endwin();
X					exit(1);
X				}
X			}
X		}
X		fclose(file);
X		if (! reads) {
X			unlink(wmrc);
X			return(firstwindow(0));
X		}
X		repaint(topw);
X	}
X	else {
X		showmsg("Please create the first window: Move to lower left, then type x");
X		okflg = FALSE;
X		while (!okflg) {
X			if (getpos(&y1, &x1, LINES-2, 0))
X				closeup(), endwin(), exit(1);
X			showmsg("Move to upper right, then type x");
X			if (getpos(&y2, &x2, y1, x1))
X				closeup(), endwin(), exit(1);
X			begline = y2;
X			begcol = x1;
X			lines = y1 - y2 + 1;
X			cols = x2 - x1 + 1;
X			if (lines > 0 && cols > 0) {
X				if (makewin(lines, cols, begline, begcol)){
X					okflg = TRUE;
X					repaint(topw);
X					showmsg("Created new window");
X				}
X				else {
X					showmsg("Can't create any shells--sorry");
X					closeup();
X					endwin();
X					exit(1);
X				}
X			}
X			else
X				showmsg("Illegal window size: Move to lower left, then type x");
X		}
X	}
X}
X
X/*
X * Set up win structure and associated junk for new window
X * Return TRUE if it worked (ie, the pty and fork in shell were ok)
X * else FALSE
X */
Xmakewin(lines, cols, begline, begcol)
Xint lines, cols, begline, begcol;
X{
X	register struct win_struct *wsp;
X
X	if ((wsp = malloc(sizeof (struct win_struct))) == NOWIN)
X		return(FALSE);
X	wsp->next = wsp->prev = 0;
X	wsp->virt = newwin(0, 0, 0, 0);
X	wsp->virt->_flags = 0; /* get around curses bug */
X	werase(wsp->virt);
X	wsp->wptr = newwin(lines, cols, begline, begcol);
X	wsp->wptr->_flags = 0; /* get around curses bug */
X	if ((wsp->buf = (char *)malloc(RDBSIZE)) == 0 || shell(wsp) == FALSE) {
X		werase(wsp->virt);
X		freespace(wsp);
X		return(FALSE);
X	}
X	wmove(wsp->virt, wsp->virt->_maxy - wsp->wptr->_maxy, 0);
X	setupbox(wsp);
X	chgwin(wsp);
X	return(TRUE);
X}
X
X/*
X * spawn shell process for window wsp
X * Finds first available pty and its matching pts and opens them
X * Returns TRUE if it found you some pty's else FALSE
X */
Xshell(wsp)
Xregister struct win_struct *wsp;
X{
X	char ptyname[100], ptsname[100], pchar;
X	int fpty, fpts;
X
X	for (pchar = PTFIRST; pchar <= PTLAST; pchar++) {
X		sprintf(ptyname, PTYFORMAT, PTYBASENAME, pchar);
X		fpty = open(ptyname, 2);
X		if (fpty >= 0) {
X			sprintf(ptsname, PTYFORMAT, PTSBASENAME, pchar);
X			fpts = open(ptsname, 2);
X			if (fpts >= 0)
X				break;
X			close(fpty);
X		}
X	}
X	if (pchar > PTLAST)
X		return(FALSE);
X	wsp->suffix = pchar;
X	for (pchar = 'a'; pchar <= 'z'; ++pchar)
X		if (getwpnt(pchar) == NOWIN)
X			break;
X	wsp->id = pchar;
X	ioctl(fpty, TIOCSETD, &ttydisc);
X	stty(fpty, &sgttybuf);
X	ioctl(fpty, TIOCSETC, &tcharsbuf);
X	ioctl(fpty, TIOCLSET, &ttymode);
X	ioctl(fpty, TIOCSLTC, &ltcharsbuf);
X	switch(wsp->pid = fork()) {
X	case 0: /* child */
X		close(fpty);
X		dup2(fpts, 0);
X		dup2(fpts, 1);
X		dup2(fpts, 2);
X		close(fpts);
X		setpgrp(0, getpid());/* set me up in my own new process group */
X		execlp(shellpgm, shellname, 0);
X		exit(1);
X	default:
X		close(fpts);
X		wsp->pty = fpty;
X		wsp->flags = 0;
X		if (symlink(ptsname, ptslinkname(wsp->id)) == 0)
X			wsp->flags = WPTSLINK;
X		setenv(wsp);
X		return(TRUE);
X	case -1: /* error */
X		close(fpty);
X		close(fpts);
X		return(FALSE);
X	}
X}
X
X#define TERMCAP "wm|wmvirt:am:bs:ce=\\EK:cl=\\ES:nd=\\EC:up=\\EA:cm=\\EY%+ %+ :"
X#ifdef	REVVIDEO
X# define REV "so=\\EO:se=\\EE:"
X#else
X# define REV ""
X#endif
X
X/*
X * send a setenv command for wmvirt terminal to shell in window wsp
X */
Xsetenv(wsp)
Xregister struct win_struct *wsp;
X{
X	char buf[LINEBUF];
X
X	if (strcmp(shellname, "csh") == 0)
X	    sprintf(buf, "setenv TERM wmvirt;setenv TERMCAP '%sco#%d:li#%d:%s'\n",
X		TERMCAP, wsp->wptr->_maxx, wsp->wptr->_maxy, REV);
X	else
X	    sprintf(buf, "TERM=wmvirt; TERMCAP='%sco#%d:li#%d:%s';export TERM TERMCAP\n",
X		TERMCAP, wsp->wptr->_maxx, wsp->wptr->_maxy, REV);
X	write(wsp->pty, buf, strlen(buf));
X}
X
Xchar *
Xptslinkname(c)
Xchar c;
X{
X	static char lnk[100];
X
X	return(sprintf(lnk, "Window%c", c));
X}
X
Xstruct win_struct *
Xaskwpnt(str, oneok)
Xchar *str;
X{
X	struct win_struct *wsp;
X	char buf[40], c;
X
X	if (topw->next == topw) {
X		if (oneok)
X			return(topw);
X		showmsg("Only 1 window");
X		return(NOWIN);
X	}
X	showmsg(sprintf(buf, "%s which window?", str));
X	if (isupper(c = bgetch(0)))
X		c = tolower(c);
X	if ((wsp = getwpnt(c)) == NOWIN)
X		showmsg("No such window");
X	return(wsp);
X}
X
X/*
X * translate window name to window pointer
X */
Xstruct win_struct *
Xgetwpnt(c)
Xchar c;
X{
X	register struct win_struct *wsp;
X	int atlast;
X
X	for (atlast = 0, wsp = topw; topw && atlast == 0; wsp = wsp->next) {
X		atlast = (wsp->next == topw);
X		if (wsp->id == c)
X			return(wsp);
X	}
X	return(NOWIN);
X}
X
X/*
X * print a command summary over the top of the screen, then redraw
X */
Xhelpmsg()
X{
Xprintf("All WM commands consist of COMMAND character plus one more character.\r\n");
Xprintf("The command character is initially ESCAPE, unless you reset it.\r\n");
Xprintf("To enter the command character itself, type it twice.\r\n\n");
Xprintf("The WM commands are COMMAND character plus:\r\n");
Xprintf("q or Q     Quit WM. 'Q' doesn't update .wmrc\r\n");
Xprintf("r          Redraw entire screen\r\n");
Xprintf("c          Change to another window\r\n");
Xprintf("l          change to Last-used window\r\n");
Xprintf("n          make a New window\r\n");
Xprintf("m          Move and/or change size of window\r\n");
Xprintf("e          Erase window temporarily\r\n");
Xprintf("k          Kill window permanently\r\n");
Xprintf("p          Page window forward (as opposed to standard scrolling)\r\n");
X#ifdef	SIGTSTP
Xprintf("z          suspend wm (Do this ONLY if you are using CSH)\r\n");
X#endif
Xprintf("C          change COMMAND character\r\n");
Xprintf("L          list windows\r\n");
X#ifdef	SHOWMAP
Xprintf("M          display map\r\n");
X#endif
Xprintf("h or ?     print this command summary\r\n\n");
Xprintf("If you are asked 'which window?' the window names are a, b, c, etc...\r\n");
Xprintf("The name of each window is shown at the top of the window.\r\n");
Xprintf("To move cursor, use 'u', 'd', 'r' and 'l' for 'up, 'down', 'right' and 'left'\r\n");
X}
X
Xshowwindows()
X{
X	register struct win_struct *wsp;
X	register WINDOW *wp;
X	int atlast, n;
X
X	printf("\n\n\n\r");
X	printf(" # ID  PID      Device     Coord.(X/Y)  Lines  Cols  State\n\r");
X	printf("-- -- -----  ------------  -----------  -----  ----  -----\n\r");
X	for (n = 1, atlast = 0, wsp = topw; atlast == 0; wsp = wsp->next, n++) {
X		atlast = (wsp->next == topw);
X		wp = wsp->wptr;
X#ifdef	NUMSUFFIX
X		printf("%2d  %c %5d  %11.11s%-2d %5d/%-5d  %4d  %4d   %s%s%s\r\n",
X#else
X		printf("%2d  %c %5d  %11.11s%c  %5d/%-5d  %4d  %4d   %s%s%s\r\n",
X#endif
X			n, wsp->id, wsp->pid, PTSBASENAME, wsp->suffix,
X			wp->_begx, wp->_begy, wp->_maxy, wp->_maxx,
X			wsp->flags & WERASED? "Erased": "Live",
X			wsp->flags & WFULLSCREEN? "/Full-screen": "",
X			wsp->flags & WPTSLINK? "/Linked": "");
X	}
X}
________This_Is_The_END________
echo 'sh - wm.h'
sed 's/^X//' <<'________This_Is_The_END________' 			>>wm.h
X/*
X * definitions for wm
X */
X
X#include <curses.h>
X#define MENLO_JCL	/* for 2.9 - get SIGTSTP from signal.h */
X
X/*
X * The number of windows for each user is limited by the number of
X * open files a process (i.e., main) may have, by the number of
X * processes each user may create and by the number of virtual tty's
X * available. (PTLAST - PTFIRST) sets a limit on the number of
X * windows available to each 'wm' process.
X *
X *
X * PTYBASENAME is the special file name of the controlling PTY's
X * available to wm, sans the last character
X * PTSBASENAME is the special file name of the slave PTY's,
X * sans last character
X * PTFIRST through PTLAST are all the final characters
X * of the special file names. If the names have a numeric suffix,
X * define NUMSUFFIX
X *
X * Likely names on 4.1bsd would be something like
X * /dev/ptypA ... for controlling and
X * /dev/ttypA ... for slave
X *
X * These PTY's should be separate from those used by networks,
X * since these should not automatically run login
X * (i.e., they should not be enabled in /etc/ttys)
X */
X
X# define PTYBASENAME	"/dev/wm/pty"		/* must be string */
X# define PTSBASENAME	"/dev/wm/pts"		/* must be string */
X#ifdef	NUMSUFFIX
X# define PTFIRST	0			/* must be int */
X# define PTLAST		8			/* must be int */
X# define PTYFORMAT	"%s%d"
X#else
X# define PTFIRST	'A'			/* must be char */
X# define PTLAST		'F'			/* must be char */
X# define PTYFORMAT	"%s%c"
X#endif
X
X# define LINEBUF	256	/* size of line buffers */
X# define MIN(a,b)	(a<b?a:b)
X# define MAX(a,b)	(a>b?a:b)
X# define showcursor(y, x)	move(y, x), refresh()
X# define ttyclear()		clear(), refresh()
X
X/*
X * flags
X */
X# define WTOUCHED	0x01	/* The window is modified */
X# define WERASED	0x02	/* The window is erased */
X# define WFULLSCREEN	0x04	/* The window is a full screen window */
X# define WPTSLINK	0x08	/* Slave pty was linked */
X
X/*
X * Global data with miscellaneous information about each window.
X */
Xstruct win_struct {
X    struct win_struct *next;	/* pointer to next window */
X    struct win_struct *prev;	/* pointer to prev window */
X    WINDOW *wptr;		/* ptr to small curses win to be displayed */
X    WINDOW *virt;		/* ptr to large curses win in case chg size */
X    WINDOW *boxtop, *boxbot;	/* ptrs to curses wins for box or 0 */
X    WINDOW *boxleft, *boxright;	/* ptrs to curses wins for box or 0 */
X    char pend[4];		/* pending characters from recent add()s */
X    char *buf;			/* read buffer */
X    int pid;			/* pid of this wondow's shell */
X    int pty;			/* fildes of pty to/from this win's shell */
X    char id;			/* name of the window */
X    char suffix;		/* last character of the virtual tty's name */
X    char flags;			/* global flags */
X};
X
Xstruct win_struct *malloc();
Xextern struct win_struct *botw, *topw;
X
X/*
X * If FAST is defined, the window copy routine will use routines that are
X * not necessarily portable.
X */
X#ifdef	FAST
X    typedef short		map_t;
X#   define mapchar(c)		((c) & 0xff)
X#   define chartomap(c, n)	((map_t)(c) | ((n) << 8))
X#   define maptocount(c)	((c) >> 8)
X# else
X    typedef char		map_t;
X#   define mapchar(c)		(c)
X#endif
X
Xextern map_t *winmap;
X#define visible(w, x, y) (winmap[(y)*COLS+(x)] == mapchar((w)->id))
X
X/*
X * This is what goes in .wmrc to recreate same layout.
X */
Xstruct sw_buf {
X    int sw_begline;
X    int sw_begcol;
X    int sw_lines;
X    int sw_cols;
X    char sw_cmdchar;
X};
X
X/* command char for virtual terminal special functions. Check TERMCAP in wm.c */
X#define CODE '\033'
X
X/*
X * Forward references
X */
Xchar *getenv();
XFILE *fopen();
Xint onsusp();
Xchar *sprintf(), *strcpy(), *strcat(), *rindex();
Xchar windowname(); int windownum();
________This_Is_The_END________
---------------------------- cut here -------------------------------

 Chris Bertin            :         (617) 933-7735 x2336
 Pixel Systems Inc.      :	   (800) 325-3342
 300 Wildwood street     :  {allegra|ihnp4|cbosgd|ima|genrad|amd|harvard}\
 Woburn, Ma 01801        :     !wjh12!pixel!pixutl!chris



More information about the Mod.sources mailing list