|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - downloadIndex: ┃ T m ┃
Length: 11326 (0x2c3e) Types: TextFile Names: »misc.c«
└─⟦87ddcff64⟧ Bits:30001253 CPHDIST85 Tape, 1985 Autumn Conference Copenhagen └─ ⟦this⟧ »cph85dist/wm/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 */ 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 */ }