Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site seismo.UUCP Posting-Version: version B 2.10.2 9/3/84; site genrad.UUCP Path: seismo!cbosgd!ulysses!allegra!mit-eddie!genrad!sources-request From: sources-request@genrad.UUCP Newsgroups: mod.sources Subject: wm - a window manager (part 3 of 4) Message-ID: <1001@genrad.UUCP> Date: 3 Aug 85 14:07:09 GMT Sender: john@genrad.UUCP Lines: 2150 Approved: john@genrad.UUCP Mod.sources: Volume 2, Issue 33 Submitted by: Tom Truscott #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # misc.c # save.c # shell.c # vterm.c # wlist.c # wm.c # This archive created: Fri Aug 2 13:13:19 1985 export PATH; PATH=/bin:$PATH echo shar: extracting "'misc.c'" '(11326 characters)' if test -f 'misc.c' then echo shar: will not over-write existing file "'misc.c'" else sed 's/^X//' << \SHAR_EOF > 'misc.c' /* ************* * DISTRIBUTION NOTICE July 30 1985 * A Revised Edition of WM, by Matt Lennon and Tom Truscott, * Research Triangle Institute, (919) 541-7005. * Based on the original by Robert Jacob (decvax!nrl-css!jacob), * Naval Research Laboratory, (202) 767-3365. * No claims or warranties of any sort are made for this distribution. * General permission is granted to copy, but not for profit, * any of this distribution, provided that this notice * is always included in the copies. ************* */ /* * Miscellaneous routines for the window manager. */ #include "wm.h" /* * Get next unused slot in window structure array. * Returns slot number, or -1 if no slot available. */ int GetSlot() { register int w; for (w = MINWINDOW; w < MAXWINDOWS; w++) if (!(win[w].flags&INUSE)) return(w); return(-1); } /* * Prompt user for a window name. */ askwindow() { register int w, c; w = -1; c = tty_getch(); if (c == CANCEL1 || c == CANCEL2) showmsg("Canceled."); else if (c == 'l') { if (iswindow(lastw)) w = lastw; else showmsg("No last window."); } else { if ( ! isdigit(c)) showmsg("Indicate window by number, or 'l' for last window."); else if ( ! iswindow(ctoi(c))) showmsg("Window #%d does not exist.", ctoi(c)); else w = ctoi(c); } return(w); } /* * Reshape window. * Returns 0 on normal completion, -1 otherwise. * On abnormal completion (e.g. the user cancels) * if this is a new window (flag) it will be deleted, * otherwise it is restored to its original state.. * In the impossible(?) event that the window cannot * be restored it is deleted, sorry. */ getbounds(w, flag) register int w; int flag; { register WINDOW *wp, *twp; /* Unpleasant hack: we save the real window contents while * a stunt double gets moved about. */ wp = win[w].wptr; if ((win[w].wptr=newwin(wlines(wp),wcols(wp),wbegy(wp),wbegx(wp)))==NULL) { win[w].wptr = wp; showmsg("Cannot allocate temporary window!"); return(-1); } showmsg("Move cursor to lower left corner (using hjkl), then type x."); if (getpos(w, 0) != 0) { delwin(win[w].wptr); win[w].wptr = wp; if (flag||NewWindow(w, wlines(wp), wcols(wp), wbegy(wp), wbegx(wp))) { WListDelete(w); FreeWindow(w); } RedrawScreen(); return(-1); } showmsg("Now move cursor to upper right corner, then type x."); if (getpos(w, 1) != 0) { delwin(win[w].wptr); win[w].wptr = wp; if (flag||NewWindow(w, wlines(wp), wcols(wp), wbegy(wp), wbegx(wp))) { WListDelete(w); FreeWindow(w); } RedrawScreen(); return(-1); } twp = win[w].wptr; win[w].wptr = wp; if (NewWindow(w, wlines(twp), wcols(twp), wbegy(twp), wbegx(twp))) { delwin(twp); WListDelete(w); FreeWindow(w); RedrawScreen(); return(-1); } delwin(twp); RedrawScreen(); return(0); } /* * Key definitions used only by routine getpos * These keys are used only for entering position of new window */ # define RIGHTCHAR 'l' # define UPCHAR 'k' # define LEFTCHAR 'h' # define DOWNCHAR 'j' # define BIGRIGHTCHAR 'L' /* jump */ # define BIGUPCHAR 'K' /* one-fifth of the */ # define BIGLEFTCHAR 'H' /* way across */ # define BIGDOWNCHAR 'J' /* the screen */ # define EXECCHAR 'x' /* * move window on screen using UPCHAR, etc. * If flag is 0, then window is dragged at lower left. * If flag is non-zero, then window is re-sized at upper right. * Does not permit bottom (y=LINES-1) line, as it is saved for messages * Returns 0 on normal completion, -1 if user cancels. */ getpos(w, flag) int w, flag; { register WINDOW *wp; register int x0, y0; register int c; int bigvert, bighoriz; int lines, cols; /* original size of window */ int aline, acol; /* 'anchored' corner of window */ int top, bot, left, right; bigvert=LINES/5+1; bighoriz=COLS/5+1; wp = win[w].wptr; lines = wlines(wp); cols = wcols(wp); y0 = wbegy(wp)+lines-1; x0 = wbegx(wp); if (flag) { /* re-size box */ aline = y0; acol = x0; y0 = wbegy(wp); x0 = wbegx(wp)+cols-1; } RedrawScreen(); (void) movecursor(y0,x0); (void) fflush(stdout); while ((c = tty_getch()) != EXECCHAR) { switch (c) { case KEY_HOME: x0=y0=0; break; case KEY_RIGHT: case RIGHTCHAR: x0 += 1; break; case KEY_UP: case UPCHAR: y0 -= 1; break; case KEY_BACKSPACE: case KEY_LEFT: case LEFTCHAR: x0 -= 1; break; case KEY_DOWN: case DOWNCHAR: y0 += 1; break; case BIGRIGHTCHAR: x0 += bighoriz; break; case BIGUPCHAR: y0 -= bigvert; break; case BIGLEFTCHAR: x0 -= bighoriz; break; case BIGDOWNCHAR: y0 += bigvert; break; default: if (c == CANCEL1 || c == CANCEL2) { showmsg("Canceled."); return(-1); } else flash(); break; } x0 = MAX(x0, 0); x0 = MIN(x0, COLS-1); y0 = MAX(y0, 0); y0 = MIN(y0, LINES-2); if (!flag) { /* drag box */ bot = y0; left = x0; top = y0+1 - lines; top = MAX(top, 0); right = x0+cols-1; right = MIN(right, COLS-1); } else { /* re-size box */ bot = MAX(y0, aline); left = MIN(x0, acol); top = MIN(y0, aline); right = MAX(x0, acol); } if (NewWindow(w, bot+1-top, right+1-left, top, left)) return(-1); wp = win[w].wptr; if (!tty_inputpending()) { RedrawScreen(); (void) movecursor(y0,x0); (void) fflush(stdout); } } return(0); } /* * If c is a control character, make it printable, * e.g. '\007' ==> '^G'. */ char * mkprint(c) register int c; { static char pbuf[3]; pbuf[0] = (c>='\040' && c<'\177' ? c : '^'); pbuf[1] = (c<'\040' ? c+0100 : c<'\177' ? '\0' : '?'); pbuf[2] = '\0'; return(pbuf); } /* * Send a setenv command for wmvirt terminal to shell in window w. * Note: this is a sad kludge. If fails if 'vi' or anything * other than the wm-activated shell is active in the window. * It is rumored that 4.3 BSD supports an ioctl to change * the window size (and corresponding signals that are understood * by screen managers). That will provide a better alternative. * Note: the setenv hack will still be needed for sessions * on remote machines via "tip". * Rlogin should (in 4.2 BSD does not) pass along TERMCAP * in addition to TERM. * * mode 0 -- disconnect termcap (unlink sneakytermcap file) * mode 1 -- set termcap, attempting sneaky termcap method first. * mode 2 -- set termcap, storing termcap string in environment * mode 3 -- set termcap by writing a shell command to the window */ XSetTerm(w, mode) register int w, mode; { register int i, fd; register char *s, *lasts; #ifdef SNEAKYTERMCAP if (mode < 3) { /* * Use of /tmp to hold the termcap files is a security hole * on most UNIX systems. Safer, but more trouble, * would be to put these files in a directory in the * users home directory. */ char termfile[100]; int oldmask; (void) sprintf(termfile, "/tmp/WM.%d.%d", (mode==1? getppid(): getpid()), w); (void) unlink(termfile); if (mode == 0) return; if (mode == 1) { (void) setenv("TERM", "wmvirt"); (void) setenv("TERMCAP", termfile); } s = termcap(w); oldmask = umask(0); fd = creat(termfile, 0644); (void) umask(oldmask); if (fd >= 0 && write(fd, s, strlen(s)) == strlen(s) && write(fd, "\n", 1) == 1 && close(fd) == 0) return; if (fd >= 0) (void) close(fd); if (mode == 1) { (void) setenv("TERMCAP", s); return; } /* gotta do it the ugly way ... */ } #endif if (mode == 0) return; /* As suggested by Dave Eckhardt (psuvax1!dae), we check for * shellnames *ending* with csh as a clue that a csh is runnning. * (This check is also made by the SUSPEND command.) */ if ((i = strlen(shellname)) >= 3 && strcmp(shellname+i-3,"csh") == 0) s = "\nsetenv TERM wmvirt; setenv TERMCAP '"; else s = "\nexport TERM TERMCAP; TERM=wmvirt; TERMCAP='"; fd = win[w].pty; (void) write(fd, s, strlen(s)); s = termcap(w); /* This crazy loop attempts to shield special chars from the tty driver, * and to fold the lines to avoid bumping into TTYHOG. * A TTYHOG of 255 is much too small, but lots of systems have that. */ lasts = s; for (i = 0; s[i]; i++) { if (s[i] == killchar() || s[i] == erasechar()) { if (i) (void) write(fd, s, i); (void) write(fd, "\\", 1); s += i; i = 0; } else if (s[i] == ':' && i+(s-lasts) > 180 && i > 0 && s[i-1] != '\\') { (void) write(fd, s, i+1); (void) write(fd, "\\\r:", 3); s += i+1; lasts = s; i = 0; } } (void) write(fd, s, strlen(s)); (void) write(fd, "'\n", 2); } /* * Find the largest unobscured rectangle on the screen, * returning its description as (lines, cols, begline, begcol) * via reference parameters. * The window being fitted is 'w'. * Returns -1 if no unobscured rectangle is found. * * Note: this algorithm is based on one from Jon Bentley's * "Programming Pearls" column in the CACM. Many readers * independently discovered the algorithm, including some * who wrote to Bentley and got mentioned in his column (sigh). * An interesting question is, is there a faster algorithm? * (Faster in the worst case, that is.) */ fitwindow(w, lp, cp, blp, bcp) int w, *lp, *cp, *blp, *bcp; { short *wbase; /* vaguely like a WINDOW pointer */ register short *wptop, *wpbot; /* Ye Olde manual code optimization */ register int x, ytop, ybot; int bestarea, bestsofar, besttohere, bestx; /* Allocate an appropriately sized array */ if (LINES > 32000 || (wbase = alloc(LINES*COLS, short)) == NULL) return(-1); /* Compute cumulative coverage table in LINES*COLS steps */ /* This is probably the slower loop, due to the subroutine call */ for (x = 0; x < COLS; x++) for (ytop=0,wptop=wbase+x; ytop < LINES-1; ytop++,wptop+=COLS) wptop[0] = covers(w, ytop, x) + ((ytop > 0)? wptop[-COLS]: 0); /* Find largest rectangle in LINES*LINES/2*COLS steps */ bestarea = 0; for (ytop = 0; ytop < LINES-1; ytop++) { for (ybot = ytop; ybot < LINES-1; ybot++) { /* Find largest rectangle in this strip */ bestsofar = besttohere = 0; wptop = wbase + (ytop-1)*COLS; for (x=0,wpbot=wbase+ybot*COLS; x < COLS; x++,wpbot++,wptop++) { if (wpbot[0] - ((ytop > 0)? wptop[0]: 0)) besttohere = 0; else if (++besttohere > bestsofar) { bestsofar = besttohere; bestx = x+1 - bestsofar; } } if (bestsofar*(ybot+1-ytop) > bestarea) { bestarea = bestsofar*(ybot+1-ytop); *lp = ybot+1-ytop; *cp = bestsofar; *blp = ytop; *bcp = bestx; } } } free((char *)wbase); if (bestarea <= 0) return(-1); return(0); } /* * Returns "" if n == 1, otherwise "s". * Useful for printing messages such as "1 line" or "2 lines". */ char * plural(n) int n; { return (n == 1? "": "s"); } /* * This routine is equivalent to 'malloc', * but returns a 'double *' which makes lint happier. * If only malloc were declared this way in the lint library * this kludge would be unnecessary. */ double * Malloc(n) unsigned int n; { extern char *malloc(); /* The tyranny of the lint library */ return((double *)malloc(n)); /* Ignore lint warning */ } SHAR_EOF if test 11326 -ne "`wc -c < 'misc.c'`" then echo shar: error transmitting "'misc.c'" '(should have been 11326 characters)' fi fi # end of overwriting check echo shar: extracting "'save.c'" '(4419 characters)' if test -f 'save.c' then echo shar: will not over-write existing file "'save.c'" else sed 's/^X//' << \SHAR_EOF > 'save.c' /* ************* * DISTRIBUTION NOTICE July 30 1985 * A Revised Edition of WM, by Matt Lennon and Tom Truscott, * Research Triangle Institute, (919) 541-7005. * Based on the original by Robert Jacob (decvax!nrl-css!jacob), * Naval Research Laboratory, (202) 767-3365. * No claims or warranties of any sort are made for this distribution. * General permission is granted to copy, but not for profit, * any of this distribution, provided that this notice * is always included in the copies. ************* */ /* * save.c M. Lennon 2/07/85 * Save and restore windows between WM sessions. */ #include "wm.h" /* Save windows from this session in HOME/.wmrc. * * Produces an ascii file containing info * necessary for restoring windows in next WM session. */ XSave(file) char *file; /* name of save file */ { register FILE *fp; /* save file pointer */ register WINDOW *w; register int i; if (*file == '\0') return(FALSE); if ((fp=fopen(file,"w")) == NULL) return(FALSE); fprintf(fp, "%s\n", mkprint(prefix)); for (i=botw; i>=0; i=win[i].next) { w = win[i].wptr; fprintf(fp, "%d %d %d %d %d\n", i, (win[i].flags&YFLEX)? 0: wlines(w), (win[i].flags&XFLEX)? 0: wcols(w), wbegy(w), wbegx(w)); } (void)fclose(fp); return(TRUE); } /* * Restore windows from previous session * as stored in ~/.wmrc. * Returns number of windows restored (0 on error). */ Restore(file) char *file; /* name of restore file */ { register FILE *fp; /* restore file pointer */ int w; /* window index */ int lines, cols, begline, begcol; /* window parameters */ int count; /* number of windows restored */ int lshrink, cshrink; /* amount that windows must be shrunk to fit */ int rc; /* temporary to hold return code from fscanf */ char ccbuf[10], tbuf[100]; /* temporary buffers */ register char *p; /* temp pointer into tbuf */ /* Open save/restore file. */ if (*file == '\0') return(0); if ((fp=fopen(file,"r")) == NULL) { showmsg("\007Cannot read '%s'.", file); sleep(2); return(0); } /* Read first line of ~/.wmrc to get the WM prefix character. */ if (fscanf(fp,"%2s%1[\n]", ccbuf, tbuf) != 2) { (void)fclose(fp); showmsg("\007Bad .wmrc file '%s'.", file); sleep(2); return(0); } if (ccbuf[0]=='^' && ccbuf[1]) prefix = (ccbuf[1]=='?' ? '\177' : ccbuf[1]-0100); else prefix = ccbuf[0]; /* Restore the windows. * Stop trying if input error encountered. */ count = 0; for (;;) { /* Read window parameters. * Check for end of file, format error, * bad window name, and bad window dimensions. */ rc = fscanf(fp,"%d%d%d%d%d%1[\n]", &w,&lines,&cols,&begline,&begcol,tbuf); if (rc == EOF) break; if (rc != 6 || lines < 0 || cols < 0 || begline < 0 || begcol < 0 || w < MINWINDOW || w >= MAXWINDOWS || (win[w].flags&INUSE)) { showmsg("\007Bad window entry, file '%s'.", file); sleep(2); break; } /* * check for "flex" windows */ if (lines == 0 && begline == 0) { lines = LINES-1; win[w].flags |= YFLEX; } if (cols == 0 && begcol == 0) { cols = COLS; win[w].flags |= XFLEX; } /* Check for windows which are beyond this screen */ /* Bug: if .wmrc is updated these windows are omitted! */ if (begline >= LINES-1 || begcol >= COLS) { showmsg("\007Window #%d is off this screen.", w); sleep(2); continue; } /* Check for windows which must be shrunk to fit */ /* Bug(?): if .wmrc is updated the new sizes are saved */ lshrink = cshrink = 0; if (begline+lines > LINES-1) { lshrink = begline+lines-(LINES-1); lines -= lshrink; } if (begcol+cols > COLS) { cshrink = begcol+cols-COLS; cols -= cshrink; } if (lshrink+cshrink) { p = tbuf; (void)sprintf(p, "\007Window #%d shrunk by", w); p += strlen(p); if (lshrink) { (void)sprintf(p, " %d line%s%s", lshrink, plural(lshrink), cshrink? " and": ""); p += strlen(p); } if (cshrink) { (void)sprintf(p, " %d column%s", cshrink, plural(cshrink)); p += strlen(p); } (void)sprintf(p, "."); showmsg("%s", tbuf); sleep(2); } /* Construct new window. */ if (NewWindow(w,lines,cols,begline,begcol)) continue; /* cannot happen? */ WListAdd(w); count++; } (void)fclose(fp); return(count); } SHAR_EOF if test 4419 -ne "`wc -c < 'save.c'`" then echo shar: error transmitting "'save.c'" '(should have been 4419 characters)' fi fi # end of overwriting check echo shar: extracting "'shell.c'" '(7153 characters)' if test -f 'shell.c' then echo shar: will not over-write existing file "'shell.c'" else sed 's/^X//' << \SHAR_EOF > 'shell.c' /* ************* * DISTRIBUTION NOTICE July 30 1985 * A Revised Edition of WM, by Matt Lennon and Tom Truscott, * Research Triangle Institute, (919) 541-7005. * Based on the original by Robert Jacob (decvax!nrl-css!jacob), * Naval Research Laboratory, (202) 767-3365. * No claims or warranties of any sort are made for this distribution. * General permission is granted to copy, but not for profit, * any of this distribution, provided that this notice * is always included in the copies. ************* */ /* * This file contains routines dealing * with the window shells. */ #include "wm.h" #include #include static struct sgttyb sgttybuf; static struct tchars tcharsbuf; static struct ltchars ltcharsbuf; static int ttymode; static int ttydisc; static int ttyfd; /* file descriptor for /dev/tty */ /* * Initialize parameters needed for creating new window shells. */ XShellInit() { (void) ioctl(0, (int)TIOCGETD, (char*)&ttydisc); (void) ioctl(0, (int)TIOCGETC, (char*)&tcharsbuf); (void) ioctl(0, (int)TIOCLGET, (char*)&ttymode); (void) ioctl(0, (int)TIOCGLTC, (char*)<charsbuf); (void) ioctl(0, (int)TIOCGETP, (char*)&sgttybuf); /* * The psuedo-tty driver should probably not produce * internal magic delay characters (cf. sys/tty.c (ttyoutput)). * It seems easiest to turn off all delays here. * (Even that is not all that easy, due to an XTABS glitch.) */ { register int i = ALLDELAY; if ((sgttybuf.sg_flags&TBDELAY) == XTABS) i &= ~TBDELAY; sgttybuf.sg_flags &= ~i; } /* We will use 'ttyfd' later when setting * controlling terminals for new shells. */ ttyfd = open("/dev/tty", 0); strcpy(shellpgm, getenv("SHELL") ? getenv("SHELL") : "sh"); strcpy(shellname, rindex(shellpgm,'/') ? rindex(shellpgm,'/')+1 : shellpgm); } /* * spawn shell process for window number w * Finds first available pty and its matching pts and opens them * Returns TRUE if it found you some pty's else FALSE */ NewShell(w) register int w; { static char ptlist[] = "0123456789abcdef"; char ptyname[100], ptsname[100]; /* names of pty master/slave devices */ int fpty, fpts; /* descriptors for "" "" "" */ register int c, i; /* index */ int ptydisc; extern int errno; /* Look for available pty master/slave pair. */ for (c = 'p';; c++) { for (i = 0; ptlist[i]; i++) { (void) sprintf(ptyname, "/dev/pty%c%c", c, ptlist[i]); if ((fpty = open(ptyname, 2)) < 0) { if (errno == ENOENT) return(-1); continue; } (void) sprintf(ptsname, "/dev/tty%c%c", c, ptlist[i]); if ((fpts = open(ptsname, 2)) < 0) { (void) close(fpty); continue; } /* This doesn't close the security hole, * but it helps avoid certain problems. */ if (ioctl(fpts, (int)TIOCGETD, (char *)&ptydisc) || ptydisc) { (void) close(fpts); (void) close(fpty); continue; } /* Okay, this one will do */ goto gottatty; } } gottatty:; (void) ioctl(fpty, (int)FIOCLEX, (char *)0); /* Fork a new shell. */ switch (win[w].pid=fork()) { default: /* parent */ (void) close(fpts); win[w].pty=fpty; break; case 0: /* child */ /* Set up stdin, stdout, stderr streams. */ dup2(fpts,0); dup2(fpts,1); dup2(fpts,2); if (fpts > 2) (void) close(fpts); /* Set up slave as new controlling terminal. */ SetCntrlTerm(ptsname); /* Set up process groups. */ SetProcGrp(); /* Set pty terminal attributes. */ InitPseudoTty(); /* Set env variables TERM & TERMCAP. */ #ifdef SNEAKYTERMCAP SetTerm(w, 1); #else (void) setenv("TERM", "wmvirt"); (void) setenv("TERMCAP", termcap(w)); #endif /* Exec the shell. */ execlp(shellpgm, shellname, (char *)0); exit(1); /* exec failed */ break; case -1: /* fork failed */ (void) close(fpty); (void) close(fpts); break; } return(win[w].pid < 0); } /* * Set up terminal attributes for new pseudo-tty. * The attributes are those of user's regular terminal. * This way, the pseudo-tty will behave just like user's terminal. */ InitPseudoTty() { /* Set tty discipline, edit characters, * mode, etc. */ (void) ioctl(0, (int)TIOCSETP, (char*)&sgttybuf); (void) ioctl(0, (int)TIOCSETD, (char*)&ttydisc); (void) ioctl(0, (int)TIOCSETC, (char*)&tcharsbuf); (void) ioctl(0, (int)TIOCLSET, (char*)&ttymode); (void) ioctl(0, (int)TIOCSLTC, (char*)<charsbuf); } /* * Make 'cterm' the new controlling terminal for * this process. Use TIOCNOTTY to turn off * current control terminal. Then when we open * 'cterm', it automatically becomes the new * controlling terminal. * Can you say 'kludge'? I knew you could. */ XSetCntrlTerm(cterm) char *cterm; { /* We really ought to check the return values * of these calls. Oh, well. */ (void) ioctl(ttyfd, (int)TIOCNOTTY, (char*)0); (void) close(ttyfd); ttyfd = open(cterm, 0); (void) close(ttyfd); } /* * Set up a new process group for a process. * Process group id will be the pid of the current process. * Also set up terminal process group for the benefit of * csh job control facilities. */ XSetProcGrp() { int pgrp; pgrp = getpid(); (void) setpgrp(0, pgrp); (void) ioctl(0, (int)TIOCSPGRP, (char*)&pgrp); } /* * Kill shell (process group) in window 'w'. */ KillShell(w) register int w; { if (win[w].pid <= 0) return; /* Close pty file. */ (void) close(win[w].pty); /* Send SIGHUP to all process associated * with window w. */ (void) kill(win[w].pid, SIGHUP); #ifdef SNEAKYTERMCAP SetTerm(w, 0); #endif win[w].pid = 0; } setenv(name, val) char *name, *val; { register int n, i; register char **ep, *oldval; char *namecmp(); extern char **environ; ep = environ; /* See if the environment variable is already set. */ for (n=0; ep[n]!=NULL; n++) if ((oldval=namecmp(name,ep[n])) != NULL) break; /* If the environment variable is already set and * the new value is no longer than the old one, * we can just overwrite the old one. */ if (ep[n] != NULL && strlen(oldval) >= strlen(val)) strcpy(oldval, val); /* Else we have to reallocate (name=value). */ else { /* If environment variable not already set, * we have to reallocate entire 'environ' array * with one additional slot in order to add the new variable. * Make sure to terminate array with a NULL entry. */ if (ep[n] == NULL) { if ((ep=alloc(n+2, char*)) == NULL) return(-1); for (i=0; i 'vterm.c' /* ************* * DISTRIBUTION NOTICE July 30 1985 * A Revised Edition of WM, by Matt Lennon and Tom Truscott, * Research Triangle Institute, (919) 541-7005. * Based on the original by Robert Jacob (decvax!nrl-css!jacob), * Naval Research Laboratory, (202) 767-3365. * No claims or warranties of any sort are made for this distribution. * General permission is granted to copy, but not for profit, * any of this distribution, provided that this notice * is always included in the copies. ************* */ /* * This file contains routines for low-level virtual * terminal emulation. */ #include "wm.h" #define FULLWIDTH(wp) (wcols(wp)==COLS) #define FULLSCREEN(wp) (FULLWIDTH(wp) && wlines(wp)==LINES-1) /* Termcap entry for virtual terminals. */ static char TERMCAP[]="wm|wmvirt|wm virtual terminal:am:bs:ce=\\EK:ho=\\EH:cd=\\EB:cl=\\ES:nd=\\EC:up=\\EA:cm=\\EY%+ %+ :"; #define TBUFLEN (sizeof(TERMCAP)+300) /* max length of termcap string */ extern char *tgoto(), *tparm(); /* * Add 'n' characters of 'p' to window 'w' at its current (y, x) coordinate. */ WMaddbuf(w, p, n) int w; register char *p; register int n; { register WINDOW *wp; register int y, x; register int c; /* * Are we in the midst of an escape sequence? */ while (win[w].pend[0] && --n >= 0) WMescape(w, toascii(*p++)); wp = win[w].wptr; getyx(wp, y, x); while (--n >= 0) switch (c = toascii(*p++)) { case '\t': x = (x+8) & ~07; while (x >= wcols(wp)) { WMaddbuf(w, "\n", 1); x -= wcols(wp); } wmove(wp, y = wcury(wp), x); break; case '\n': if (++y >= wlines(wp)) { --y; wmove(wp, 0, x); WMdeleteln(w); } wmove(wp, y, x); break; case '\r': wmove(wp, y, x = 0); break; case '\b': if (x>0) wmove(wp, y, --x); break; case '\007': beep(); break; case '\0': break; case ESC: win[w].pend[0] = ESC; win[w].pend[1] = '\0'; while (win[w].pend[0] && --n >= 0) WMescape(w, toascii(*p++)); getyx(wp, y, x); break; /* Dummy cases to fool pcc into generating a fast switch table */ case 01: case 02: case 03: case 04: case 05: case 06: default: if (isprint(c)) { waddch(wp, c); if (++x >= wcols(wp)) { if (++y >= wlines(wp)) { --y; wmove(wp, 0, 0); WMdeleteln(w); } wmove(wp, y, x = 0); } } else { char *s = mkprint(c); WMaddbuf(w, s, strlen(s)); getyx(wp, y, x); } break; } } /* * Construct virtual terminal escape sequence * one character at a time. * When escape sequence is complete, perform * the indicated action in window 'w'. */ WMescape(w, c) int w; int c; { register WINDOW *wp; register int y, x; register char *pend; int oldx, oldy; pend = win[w].pend; wp = win[w].wptr; getyx(wp, y, x); /* ESC-Y is a multi-character escape sequence * so we need to make sure we have all the * characters before we start processing it. */ if (c == 'Y' && pend[1] == '\0') { pend[1]=c; pend[2]='\0'; return; } else if (pend[1] == 'Y') { if (pend[2]=='\0') { pend[2]=c; return; } else { pend[3]=c; c='Y'; } } /* Process escape sequence. */ pend[0] = '\0'; /* escape no longer pending */ switch (c) { case 'Y': /* cursor motion */ y = oldy = pend[2]-' '; x = oldx = pend[3]-' '; if (x < 0) x = 0; if (y < 0) y = 0; if (x >= wcols(wp)) x = wcols(wp)-1; if (y >= wlines(wp)) y = wlines(wp)-1; if (y != oldy || x != oldx) showmsg("Bad cursor motion to (%d,%d).", oldy, oldx); wmove(wp, y, x); break; case 'K': /* clear to end of line */ wclrtoeol(wp); break; case 'B': /* clear to bottom of window */ wclrtobot(wp); break; case 'H': /* home cursor */ wmove(wp, 0, 0); break; case 'R': /* visual bell */ flash(); break; case 'D': /* delete line */ WMdeleteln(w); break; case 'L': /* insert line */ WMinsertln(w); break; case 'P': /* insert character */ #ifdef CURSEASSIST #ifndef TERMINFO if (FULLWIDTH(wp) && insert_character && !insert_null_glitch) { (void) movecursor(wbegy(wp)+y, wbegx(wp)+x); putp(insert_character); winsch(curscr, ' '); } #endif #endif winsch(wp, ' '); break; case 'Q': /* delete character */ #ifdef CURSEASSIST #ifndef TERMINFO if (FULLWIDTH(wp) && delete_character) { (void) movecursor(wbegy(wp)+y, wbegx(wp)+x); putp(delete_character); wdelch(curscr); } #endif #endif wdelch(wp); break; case 'S': /* erase window */ werase(wp); #ifdef CURSEASSIST if (FULLSCREEN(wp) && !msgbirth) clearok(curscr, TRUE); #endif break; case 'C': /* non-destructive blank */ if (++x >= wcols(wp)) { WMaddbuf(w, "\n", 1); x = 0; } wmove(wp, wcury(wp), x); break; case 'A': /* cursor up */ if (--y>=0) wmove(wp, y, x); break; case 'O': /* enter standout mode */ wstandout(wp); break; case 'E': /* leave standout mode */ wstandend(wp); break; default: { char *s; s = mkprint(ESC); WMaddbuf(w, s, strlen(s)); s = mkprint(c); WMaddbuf(w, s, strlen(s)); } break; } } /* * Insert a line just above the current line of window wp. * The cursor location in wp is not changed. */ WMinsertln(w) int w; { register WINDOW *wp; register int curline, curcol; wp = win[w].wptr; wrefresh(wp); /* smooths scrolling. Crucial for untouchwin. */ winsertln(wp); #ifdef CURSEASSIST /* If this terminal has scrolling regions, use them */ if (has_scroll_region && FULLWIDTH(wp)) { /* First, get curscr management out of the way. */ curline = cursrow(); curcol = curscol(); Cmove(wbegy(wp)+wlines(wp)-1, 0); Cdeleteln(); Cmove(wbegy(wp)+wcury(wp), 0); Cinsertln(); Cmove(curline, curcol); /* now update the screen itself */ (void) movecursor(wbegy(wp)+wcury(wp), wbegx(wp)+wcurx(wp)); putp(save_cursor); /* Save since CS garbles cursor */ putp(tgoto(change_scroll_region, wbegy(wp)+wlines(wp)-1, wbegy(wp)+wcury(wp))); putp(restore_cursor); /* CS garbles cursor */ putp(scroll_reverse); putp(tgoto(change_scroll_region, LINES-1, 0)); putp(restore_cursor); /* Once again put it back */ Untouchwin(wp); } /* Else if this terminal has scrolling rectangles, use them now. */ #ifdef SET_WINDOW else if (has_scroll_window) { overwrite(wp, curscr); /* slow but easy */ putp(tparm(set_window, wbegy(wp)+wcury(wp), wbegy(wp)+wlines(wp)-1, wbegx(wp), wbegx(wp)+wcols(wp)-1)); putp(scroll_reverse); putp(tparm(set_window, 0, LINES-1, 0, COLS-1)); /* get back to where curses thinks we are */ putp(tgoto(cursor_address, curscol(), cursrow())); Untouchwin(wp); } #endif /* Else if this terminal has ins/del line, now is the time */ else if (has_insdel_line && FULLWIDTH(wp)) { /* Open a line above current line in window wp, * then delete wp's bottom line. * Perform identical operations on curscr * as we do on the terminal itself. */ (void) movecursor(wbegy(wp)+wcury(wp), 0); putp(insert_line); Cinsertln(); (void) movecursor(wbegy(wp)+wlines(wp), 0); putp(delete_line); Cdeleteln(); RestoreMsg(); Untouchwin(wp); } #endif } /* * This routine deletes the current line in window wp. * The cursor location in wp is not changed. */ WMdeleteln(w) int w; { register WINDOW *wp; register int curline, curcol; wp = win[w].wptr; /* * See what we can do about windows that scroll slowly */ if (!(win[w].flags&FAST)) { static int lines_since_refresh = 0; if ((lines_since_refresh += 7) >= wlines(wp)) { wrefresh(wp); lines_since_refresh = 0; } wdeleteln(wp); #ifdef BUGGYTERMINFO touchwin(wp); #endif return; } wrefresh(wp); /* smooths scrolling. Crucial for untouchwin. */ wdeleteln(wp); #ifdef BUGGYTERMINFO /* wdeleteln neglects first/bottom info for the last line */ touchwin(wp); #endif #ifdef CURSEASSIST /* If we're deleting top line of a full screen window, * this is the same as scrolling. * (We do not this if we have scrolling region support * and there is a wm message, but what a bother.) */ if (FULLSCREEN(wp) && wcury(wp)==0 && !(has_scroll_region && msgbirth)) { ZapMsgLine(); /* so it doesn't scroll up into our window */ curline = cursrow(); curcol = curscol(); Cmove(0, 0); Cdeleteln(); Cmove(curline, curcol); /* Cause screen to scroll. * Since wm almost always 'wants' the cursor on LINES-2, * there is a cheap heuristic thrown in. */ (void) movecursor(LINES, curcol); #ifndef TERMINFO if (cursor_up) { putp(cursor_up); Cmove(LINES-2, curcol); } #endif RestoreMsg(); Untouchwin(wp); } /* Else if this terminal has scrolling regions, use them. */ else if (has_scroll_region && FULLWIDTH(wp)) { curline = cursrow(); curcol = curscol(); Cmove(wbegy(wp)+wcury(wp), 0); Cdeleteln(); /* it is about to be deleted */ Cmove(wbegy(wp)+wlines(wp)-1, 0); Cinsertln(); /* it is about to be cleared */ Cmove(curline, curcol); (void) movecursor(wbegy(wp)+wlines(wp)-1, wbegx(wp)+wcurx(wp)); putp(save_cursor); /* Save since CS garbles cursor */ putp(tgoto(change_scroll_region, wbegy(wp)+wlines(wp)-1, wbegy(wp)+wcury(wp))); putp(restore_cursor); /* put cursor back */ putp(scroll_forward); putp(tgoto(change_scroll_region, LINES-1, 0)); putp(restore_cursor); /* put cursor back */ Untouchwin(wp); } /* Else if this terminal has scrolling rectangles, use them. */ #ifdef SET_WINDOW else if (has_scroll_window) { overwrite(wp, curscr); /* slow but easy */ putp(tparm(set_window, wbegy(wp)+wcury(wp), wbegy(wp)+wlines(wp)-1, wbegx(wp), wbegx(wp)+wcols(wp)-1)); putp(tgoto(cursor_address, 0, wlines(wp)-1)); putp(scroll_forward); putp(tparm(set_window, 0, LINES-1, 0, COLS-1)); putp(tgoto(cursor_address, curscol(), cursrow())); Untouchwin(wp); } #endif /* Else if this terminal has insdel line, use that. */ else if (has_insdel_line && FULLWIDTH(wp)) { /* Open a line below the last line in window wp, * then delete wp's current line. */ (void) movecursor(wbegy(wp)+wlines(wp), 0); putp(insert_line); Cinsertln(); (void) movecursor(wbegy(wp)+wcury(wp), 0); putp(delete_line); Cdeleteln(); RestoreMsg(); Untouchwin(wp); } #endif } /* * Construct termcap for wmvirt terminal in window w. */ char * termcap(w) int w; { register WINDOW *wp; static char tbuf[TBUFLEN]; /* termcap buffer */ wp = win[w].wptr; (void)sprintf(tbuf, "%sco#%d:li#%d:", TERMCAP, wcols(wp), wlines(wp)); /* If terminal scrolls 'quickly', add insert/delete line to termcap. */ if ((win[w].flags&FAST) && (has_insdel_line || has_scroll_region || has_scroll_window)) strcat(tbuf, "al=\\EL:dl=\\ED:"); /* If terminal has insert/delete character options, add them here */ if (insert_character || (enter_insert_mode && exit_insert_mode)) strcat(tbuf, "ic=\\EP:"); if (delete_character) strcat(tbuf, "dc=\\EQ:"); /* If terminal has standout capabilities, add that too. */ if (enter_standout_mode && exit_standout_mode) strcat(tbuf, "so=\\EO:se=\\EE:"); /* Include vb if terminal has a visual bell */ if (flash_screen) strcat(tbuf, "vb=\\ER:"); /* Include keypad capabilities if there is room left */ if (strlen(tbuf)+strlen(keycap) < TBUFLEN) strcat(tbuf, keycap); return(tbuf); } SHAR_EOF if test 11456 -ne "`wc -c < 'vterm.c'`" then echo shar: error transmitting "'vterm.c'" '(should have been 11456 characters)' fi fi # end of overwriting check echo shar: extracting "'wlist.c'" '(3611 characters)' if test -f 'wlist.c' then echo shar: will not over-write existing file "'wlist.c'" else sed 's/^X//' << \SHAR_EOF > 'wlist.c' /* ************* * DISTRIBUTION NOTICE July 30 1985 * A Revised Edition of WM, by Matt Lennon and Tom Truscott, * Research Triangle Institute, (919) 541-7005. * Based on the original by Robert Jacob (decvax!nrl-css!jacob), * Naval Research Laboratory, (202) 767-3365. * No claims or warranties of any sort are made for this distribution. * General permission is granted to copy, but not for profit, * any of this distribution, provided that this notice * is always included in the copies. ************* */ /* * Code for rearranging window display order */ #include "wm.h" /* * Make window 'w' the new top window. * Insert 'w' into window list (keeps track * of redraw order). * 'topw' (pointer to the top window) is set to 'w'. * Recompute obscured window status. */ WListAdd(w) register int w; { register int wt; /* temporary window pointer */ /* Add w to empty list. */ if (botw < 0) botw=w; /* Add w to top of nonempty list. */ else { for (wt=botw; win[wt].next>=0; wt=win[wt].next) ; win[wt].next=w; } win[w].next = -1; topw = w; /* Recompute obscured window status */ WObscure(); } /* * Delete window 'w'. * Remove it from window list. * Recompute obscured windows. */ WListDelete(w) register int w; { register int wt; /* temporary window pointer */ if ( ! iswindow(w)) return; /* Don't read from this window any more. */ DisablePty(w); /* Delete w from list. */ if (botw==w) botw=win[botw].next; else { for (wt=botw; wt>=0; wt=win[wt].next) if (win[wt].next==w) break; if (wt>=0) win[wt].next=win[win[wt].next].next; } /* Find new topw. */ wt=botw; while (wt>=0 && win[wt].next>=0) wt=win[wt].next; topw=wt; /* Recompute obscured window info */ WObscure(); } /* * Recompute obscured ('blocked') and 'covers' information * Enable/Disable ptys appropriately. */ WObscure() { register int w, wt, i; for (w = botw; w >= 0; w = win[w].next) { EnablePty(w); win[w].flags &= ~BLOCKED; for (i = 0; i < MAXWINDOWS; i++) win[w].covers[i] = FALSE; for (wt = botw; wt != w; wt = win[wt].next) { if (!overlap(w, wt)) continue; win[w].covers[wt] = TRUE; win[wt].flags |= BLOCKED; /* We could disable the obscured window's pty at this point, * but we'll wait and do it in 'readptys()'. */ /* (we should probably disable it now if it was previously) */ } } } /* Note: the arithmetic 'bottom' is actual the visual 'top'! * Also, RIGHT and TOP are the index of the column (row) just past * the index of the window's actual right (top). */ #define BOTTOM(wp) (wbegy(wp)) #define TOP(wp) (BOTTOM(wp)+wlines(wp)) #define LEFT(wp) (wbegx(wp)) #define RIGHT(wp) (LEFT(wp)+wcols(wp)) /* * Determine if two windows overlap. * Windows must have at least a row (column) separating them * to permit the border lines to be drawn. */ overlap(w1, w2) int w1, w2; { register WINDOW *wp1, *wp2; wp1 = win[w1].wptr; wp2 = win[w2].wptr; return(LEFT(wp1) <= RIGHT(wp2) && LEFT(wp2) <= RIGHT(wp1) && BOTTOM(wp1) <= TOP(wp2) && BOTTOM(wp2) <= TOP(wp1)); } /* * Returns 1 if a window (or its border) above w cover point (y,x), * otherwise returns 0. */ covers(w, y, x) int w; register int y, x; { register int wt; register WINDOW *wp; for (wt = w; (wt = win[wt].next) >= 0;) { wp = win[wt].wptr; if (LEFT(wp) <= x+1 && x <= RIGHT(wp) && BOTTOM(wp) <= y+1 && y <= TOP(wp)) return(1); } return(0); } SHAR_EOF if test 3611 -ne "`wc -c < 'wlist.c'`" then echo shar: error transmitting "'wlist.c'" '(should have been 3611 characters)' fi fi # end of overwriting check echo shar: extracting "'wm.c'" '(12415 characters)' if test -f 'wm.c' then echo shar: will not over-write existing file "'wm.c'" else sed 's/^X//' << \SHAR_EOF > 'wm.c' /* ************* * DISTRIBUTION NOTICE July 30 1985 * A Revised Edition of WM, by Matt Lennon and Tom Truscott, * Research Triangle Institute, (919) 541-7005. * Based on the original by Robert Jacob (decvax!nrl-css!jacob), * Naval Research Laboratory, (202) 767-3365. * No claims or warranties of any sort are made for this distribution. * General permission is granted to copy, but not for profit, * any of this distribution, provided that this notice * is always included in the copies. ************* */ /* * wm.c R. Jacob 7/28/1980 * Simple multiple-window monitor for Unix * allows windows to overlap * * This is the code for the main program * * This version runs as only one process (plus the shells) * This is intended for Berkeley 4.2 VAX Unix only. */ #include "wm.h" #include #include #include #include #define LINEBUF 64 /* size of pty input buffer */ /* * Real declarations for stuff defined as extern in wm.h */ struct win_struct win[MAXWINDOWS]; /* array of windows */ int botw, topw, lastw; /* bottom, top, last windows */ int prefix = '\033'; /* prefix character */ char savefile[100]; /* name of save/restore file */ char shellname[20]; /* name of shell */ char shellpgm[100]; /* pathname of shell */ int configflag = FALSE; /* true if .wmrc config. has changed */ #ifndef TERMINFO char *change_scroll_region, *save_cursor, *restore_cursor; char *set_window; #endif int has_scroll_window = FALSE; /* true if terminal has 'usable' set_window */ int has_scroll_region = FALSE; /* true if terminal has 'usable' SR */ int has_insdel_line = FALSE; /* true if terminal has both ins+del line */ static int savereadmask; /* pty readmask */ static int childdied = FALSE; /* set when a window shell stops */ static int restorflag=TRUE; /* TRUE if we're restoring windows */ static int MaxQueued = 150; static long pausetime = 200000L; static int clamp_down; /* number of chars to remain snappy after ctrl-S */ static int Divisor; /* read/write reduction factor */ main(argc, argv) int argc; char *argv[]; { register int c; /* input character */ int readmask; /* temp pty readmask */ register int w; /* window index */ register int quit = FALSE; /* Did user give the 'quit' command? */ register struct timeval *tp; struct timeval timeout; register char *s; setbuf(stdout, alloc(BUFSIZ, char)); DoCmdArgs(argc, argv); Startup(); /* Adjust MaxQueued and pausetime values for fast terminals */ { int ttyspeed; if ((ttyspeed = baudrate()) > 4800) { pausetime /= 2; if (ttyspeed > B9600) MaxQueued *= 2; } } /* Try to restore window arrangement from a previous * WM session. 'Restore()' returns number of windows restored. * If no windows restored, start from scratch, * providing user with a full screen window. */ ClearScreen(); if (restorflag==FALSE || Restore(savefile) <= 0) { if (savefile[0] == '\0') strcpy(savefile, ".wmrc"); w = GetSlot(); if (NewWindow(w, LINES-1, COLS, 0, 0)) { showmsg("Sorry, can't create any windows."); FreeWindow(w); Shutdown(1); } WListAdd(w); } RedrawScreen(); showmsg("Welcome to WM. Type %sh for help.", mkprint(prefix)); RestoreCursor(); /* Main processing loop. */ do { if (childdied) ReapShell(); /* If the shell in the top window has died (pid == -1), * or was never started to begin with (pid == 0), * start a new shell. */ if (win[topw].pid <= 0) { if (win[topw].pid < 0) showmsg("\007Shell in current window died. Restarting..."); if (NewShell(topw)) { showmsg("\007Sorry, can't start up new shell."); win[topw].pid = -1; } else EnablePty(topw); RestoreCursor(); } /* Poll user's terminal and ptys. */ readmask = savereadmask; tp = 0; Divisor = (clamp_down? 4: 1); #ifdef TIOCOUTQ { long n; if (ioctl(1, (int)TIOCOUTQ, (char*)&n)==0 && n > MaxQueued/Divisor) { readmask &= 01; tp = &timeout; tp->tv_sec = 0; tp->tv_usec = pausetime/Divisor; } } #endif if (select(8*sizeof(readmask), &readmask, 0, 0, tp) <= 0) continue; /* Terminate messages after a few seconds */ if (msgbirth && abs(time((time_t *)0) - msgbirth) > 3) showmsg(""); /* If no input from the user, read ptys. */ if ((readmask&01) == 0) { readptys(readmask); continue; } /* If user input is not the WM command prefix character, * just send input to the appropriate pty. */ do { if ((c = tty_getch()) != prefix) { (void)write(win[topw].pty, tty_text, tty_textlen); if (c == CTRL(S)) clamp_down = LINES*COLS/2; } /* Process WM command. */ else { showmsg("#%d Command?", topw); c = tty_getch(); showmsg(""); if (c != prefix) quit = docmd(c); else (void)write(win[topw].pty, tty_text, tty_textlen); RestoreCursor(); } } while (tty_backcnt > 0); } while ( ! quit); /* If user has changed the window configuration since * the session began, see if they want to save the * current configuration. */ if (restorflag && configflag) { showmsg("Save current (modified) window configuration? [no] "); c = tty_getch(); if (c != 'y' && c != 'Y') showmsg(""); else if ( (s = WPrompt("save file", savefile)) == NULL) ; else if (Save(s) != 0) showmsg("Saved current window configuration in '%s'.", s); else showmsg("Sorry, can't save current window configuration."); } /* Shut down. */ Shutdown(0); } static char USAGE[] = "[ -n ] [ -f savefile ]"; /* * Interpret command line arguments to wm. */ DoCmdArgs(argc, argv) register int argc; /* arg count */ register char *argv[]; /* arg list */ { for (argv++,argc--; argc>0; argv++,argc--) { if (**argv != '-') { fprintf(stderr, "usage: wm %s\n", USAGE); exit(1); } switch ((*argv)[1]) { case 'f': /* next arg is name of save/restore file */ strcpy(savefile, *++argv); argc--; break; case 'n': /* don't restore/save window configuration */ restorflag = FALSE; break; default: fprintf(stderr, "wm: unknown option '%s'\n", *argv); fprintf(stderr, "usage: wm %s\n", USAGE); exit(1); } } } /* * Initialize WM. */ XStartup() { register int w; /* window pointer */ int onintr(), sigchild(); /* interrupt handler */ savereadmask = 01; ShellInit(); /* this call must precede the suspend()! */ /* Catch signals. * Note: there is a tiny window from here to the return of raw(). * Signals could be ignored until then, but it is a bother. */ if (signal(SIGHUP, SIG_IGN) != SIG_IGN) (void)signal(SIGHUP, onintr); if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) (void)signal(SIGQUIT, onintr); if (signal(SIGINT, SIG_IGN) != SIG_IGN) (void)signal(SIGINT, onintr); if (signal(SIGPIPE, SIG_IGN) != SIG_IGN) (void)signal(SIGPIPE, onintr); (void)signal(SIGCHLD, sigchild); /* Initialize curses stuff. */ if ((w = (int)initscr()) == ERR || !cursor_address) { /* This ERR nonsense is for the benefit of terminfo curses. * Has initscr cleaned up correctly (e.g. reset the tty)? * I sure wish initscr always suceeded. */ if (w != ERR) endwin(); fprintf(stderr, "Sorry. Need cursor addressing to play WM\n"); /* If 'wm' is run via exec from a .profile, then exiting here * would log the luser out. Unfortunately, we cannot reliably * determine if wm's parent is a shell, so we cannot * simply exit now. */ fprintf(stderr, "Spawning a normal shell\n"); execlp(shellpgm, shellname, (char *)0); exit(1); } noecho(); raw(); leaveok(stdscr, TRUE); #ifdef TERMINFO #ifdef BUGGYTERMINFO /* buggyterminfo neglects the move_standout_mode problem */ if (!move_standout_mode) set_attributes = enter_standout_mode = exit_standout_mode = NULL; /* in buggyterminfo, idlok leads to core dumps */ #else idlok(curscr, TRUE); /* the first arg is pointless, yes? */ #endif #else /* * hack to check for scrolling-region capability (vt100) * since curses does not itself check. */ change_scroll_region = getcap("cs"); save_cursor = getcap("sc"); restore_cursor = getcap("rc"); set_window = getcap("sw"); #ifdef GAGMEKEYPAD init_keypad(); #endif #endif /* ensure there is a 'scroll_forward' string */ if (!scroll_forward) scroll_forward = "\n"; if (change_scroll_region && save_cursor && restore_cursor && scroll_reverse) has_scroll_region = TRUE; if (insert_line && delete_line) has_insdel_line = TRUE; if (set_window && scroll_reverse) has_scroll_window = TRUE; /* Init window structure array. */ topw = botw = lastw = -1; for (w=0; w=0; w=win[w].next) { if ((rmask & (01< 0) { /* It is truly amazing how complex simple things can become */ if (WIFSTOPPED(status)) { if (status.w_stopsig == SIGTTOU || status.w_stopsig == SIGTTIN) continue; /* Let's not worry about these */ showmsg("Cannot suspend a window shell."); RestoreCursor(); if ((pgrp = getpgrp(pid)) <= 0 || killpg(pgrp, SIGCONT)) (void) kill(pid, SIGCONT); /* so there! */ continue; } for (w=botw; w>=0; w=win[w].next) if (win[w].pid == pid) { DisablePty(w); KillShell(w); win[w].pid = -1; break; /* out of for loop */ } } } /* * Enable pty of window w for reading. */ EnablePty(w) register int w; /* window whose pty we're enabling */ { if (win[w].pid > 0) savereadmask |= (01 << win[w].pty); } /* * Disable pty of window w for reading. */ DisablePty(w) register int w; /* window whose pty we're disabling */ { if (win[w].pid > 0) savereadmask &= ~(01 << win[w].pty); } SHAR_EOF if test 12415 -ne "`wc -c < 'wm.c'`" then echo shar: error transmitting "'wm.c'" '(should have been 12415 characters)' fi fi # end of overwriting check # End of shell archive exit 0