home *** CD-ROM | disk | FTP | other *** search
- /*
- *************
- * 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
- */
- SetTerm(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 */
- }
-