DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T m

⟦24261772c⟧ TextFile

    Length: 11326 (0x2c3e)
    Types: TextFile
    Names: »misc.c«

Derivation

└─⟦87ddcff64⟧ Bits:30001253 CPHDIST85 Tape, 1985 Autumn Conference Copenhagen
    └─ ⟦this⟧ »cph85dist/wm/misc.c« 

TextFile

/*
 *************
 * 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 */
}