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