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 2 of 4) Message-ID: <1000@genrad.UUCP> Date: 3 Aug 85 14:06:22 GMT Sender: john@genrad.UUCP Lines: 2142 Approved: john@genrad.UUCP Mod.sources: Volume 2, Issue 32 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: # Makefile # wm.h # cmd.c # curses.c # getch.c # hacks.c # help.c # This archive created: Fri Aug 2 13:13:15 1985 export PATH; PATH=/bin:$PATH echo shar: extracting "'Makefile'" '(2215 characters)' if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else sed 's/^X//' << \SHAR_EOF > 'Makefile' # # Makefile for wm # # Flags for the C compiler. CFLAGS = -O # Flags for loader. You probably do not need any. LDFLAGS = # Final resting place of wm executable. BIN = /usr/local # Name of owner and group that you want installed wm to have. OWNER = bin GROUP = bin # Version of libcurses wm is linked with. This *must* be # the version that is distributed with wm, since it contains # several bug fixes necessary to the correct operation of wm. LIBS = -lcurses -ltermcap OBJS = cmd.o curses.o getch.o hacks.o help.o misc.o \ save.o shell.o vterm.o wlist.o wm.o XSRCS = cmd.c curses.c getch.c hacks.c help.c misc.c \ save.c shell.c vterm.c wlist.c wm.c wm: $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o wm $(OBJS): wm.h lint: lint -hbux $(SRCS) clean: /bin/rm -f *.o wm core *.out install: wm install -o $(OWNER) -g $(GROUP) -s wm $(DESTDIR)/$(BIN) depend: cat x.c for i in ${SRCS}; do \ (echo `basename $$i .c`.o: $$i >>makedep; \ /bin/grep '^#[ ]*include' x.c $$i | sed \ -e 's,<\(.*\)>,"/usr/include/\1",' \ -e 's/:[^"]*"\([^"]*\)".*/: \1/' \ -e 's/\.c/.o/' >>makedep); done echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep echo '$$r makedep' >>eddep echo 'w' >>eddep cp Makefile Makefile.bak ed - Makefile < eddep rm eddep makedep x.c echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile echo '# see make depend above' >> Makefile # DO NOT DELETE THIS LINE -- make depend uses it cmd.o: cmd.c cmd.o: wm.h curses.o: curses.c curses.o: wm.h getch.o: getch.c getch.o: wm.h getch.o: /usr/include/signal.h getch.o: /usr/include/setjmp.h getch.o: /usr/include/sys/time.h hacks.o: hacks.c hacks.o: wm.h help.o: help.c help.o: wm.h misc.o: misc.c misc.o: wm.h save.o: save.c save.o: wm.h shell.o: shell.c shell.o: wm.h shell.o: /usr/include/signal.h shell.o: /usr/include/errno.h vterm.o: vterm.c vterm.o: wm.h wlist.o: wlist.c wlist.o: wm.h wm.o: wm.c wm.o: wm.h wm.o: /usr/include/signal.h wm.o: /usr/include/sys/wait.h wm.o: /usr/include/sys/time.h wm.o: /usr/include/sys/resource.h # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above SHAR_EOF if test 2215 -ne "`wc -c < 'Makefile'`" then echo shar: error transmitting "'Makefile'" '(should have been 2215 characters)' fi fi # end of overwriting check echo shar: extracting "'wm.h'" '(6227 characters)' if test -f 'wm.h' then echo shar: will not over-write existing file "'wm.h'" else sed 's/^X//' << \SHAR_EOF > 'wm.h' /* ************* * 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. ************* */ /* * definitions for wm */ #include "curses.h" #include #include #define CURSEASSIST /* give curses a hand, sigh. */ #define SET_WINDOW /* assist all-wonderful scrolling rectangles */ #define GAGMEKEYPAD /* gross hack for arrow keys */ /*#define SNEAKYTERMCAP /* /tmp termcap kludge */ /* define TERMINFO if we are using a terminfo version of curses */ #ifdef A_STANDOUT #define TERMINFO #endif #ifdef TERMINFO /* define FASTTERMINFO if your terminfo has a clever doupdate */ /*#define FASTTERMINFO /**/ /* define BUGGYTERMINFO if your terminfo has 'certain bugs' */ #define BUGGYTERMINFO /**/ #endif /* * Definitions for curses */ #define wcury(w) ((w)->_cury) /* current (y,x) in window w */ #define wcurx(w) ((w)->_curx) #define wbegy(w) ((w)->_begy) /* window offset from origin */ #define wbegx(w) ((w)->_begx) #define wlines(w) ((w)->_maxy) /* # lines/cols in window w */ #define wcols(w) ((w)->_maxx) #define cursrow() wcury(curscr) /* current (y,x) on screen */ #define curscol() wcurx(curscr) /* stuff dependent on the version of curses */ #ifdef TERMINFO #undef GAGMEKEYPAD #ifdef FASTTERMINFO #undef CURSEASSIST #endif #undef wlines #undef wcols #define wlines(w) ((w)->_maxy+1) /* # lines/cols in window w */ #define wcols(w) ((w)->_maxx+1) #include /* undefine one of the more annoying definitions in term.h */ #ifdef lines #undef lines #endif extern WINDOW *newscr; #define Untouchwin(wp) untouchwin(wp),untouchwin(newscr) #ifdef CURSEASSIST /* curseassist cheats big */ #define Cmove(y,x) wmove(curscr,y,x),wmove(newscr,y,x) #define Cinsertln() winsertln(curscr),winsertln(newscr) #define Cdeleteln() wdeleteln(curscr),wdeleteln(newscr) #endif #else extern int *_putchar(); #define putp _puts #define enter_ca_mode TI #define cursor_address CM #define flash_screen VB #define enter_standout_mode SO #define exit_standout_mode SE #define move_standout_mode MS #define insert_line AL #define delete_line DL #define change_scroll_region CS #define scroll_reverse SR #define save_cursor SC #define restore_cursor RC #define insert_character IC #define insert_null_glitch IN #define enter_insert_mode IM #define exit_insert_mode EI #define delete_character DC #define scroll_forward NL #define cursor_down DO #define cursor_up UP #define Untouchwin(wp) untouchwin(wp) #ifdef CURSEASSIST /* curseassist cheats big */ #define Cmove(y,x) wmove(curscr,y,x) #define Cinsertln() winsertln(curscr) #define Cdeleteln() wdeleteln(curscr) #endif #endif /* key pad atrocities follow */ extern char tty_text[], keycap[]; extern int tty_textlen, tty_backcnt; #ifndef KEY_BACKSPACE #define KEY_BACKSPACE 0401 #define KEY_UP 0402 #define KEY_DOWN 0403 #define KEY_LEFT 0404 #define KEY_RIGHT 0405 #define KEY_HOME 0406 #endif #ifndef GAGMEKEYPAD #define tty_getch tty_realgetch #endif /* * The number of active windows is limited by the number of * open files a process (i.e., main) may have, * the number of processes a user or the whole system can have, * and (on an 11 but not a VAX) the memory for the per-window curses buffers. * Also, window names are limited to 0..9, i.e. at most 10 windows. */ #define MAXWINDOWS 10 /* windows #0..#9 */ #define ESC '\033' /* char for virtual terminal functions */ #define CANCEL1 '\033' /* char to cancel wm command */ #define CANCEL2 '\177' /* char to cancel wm command */ #define MINWINDOW 1 /* change this to 0 to permit window #0 */ #define iswindow(w) ((w)>=MINWINDOW && (w)=(b)? (a): (b)) #define MIN(a,b) ((a)<=(b)? (a): (b)) /* * External variables. */ extern struct win_struct win[]; /* array of windows */ extern int botw, topw, lastw; /* bottom, top, last window */ extern int prefix; /* WM command prefix character */ extern char savefile[]; /* name of save/restore file */ extern char shellname[]; /* name of shell */ extern char shellpgm[]; /* pathname of shell */ extern int configflag; /* true if window config. has changed */ extern time_t msgbirth; /* time last message was displayed */ #ifndef TERMINFO extern char *change_scroll_region, *save_cursor, *restore_cursor; extern char *set_window; #endif extern int has_scroll_window, has_scroll_region, has_insdel_line; /* * Functions returning a non-int value */ XFILE *fopen(); char *sprintf(), *strcpy(), *strcat(), *rindex(), *getenv(); char *mkprint(), *termcap(), *WPrompt(), *plural(); double *Malloc(); /* if only malloc were declared this way */ #define alloc(n,type) ((type*)Malloc((unsigned)((n)*sizeof(type)))) SHAR_EOF if test 6227 -ne "`wc -c < 'wm.h'`" then echo shar: error transmitting "'wm.h'" '(should have been 6227 characters)' fi fi # end of overwriting check echo shar: extracting "'cmd.c'" '(7983 characters)' if test -f 'cmd.c' then echo shar: will not over-write existing file "'cmd.c'" else sed 's/^X//' << \SHAR_EOF > 'cmd.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. ************* */ /* * Command interpreter for WM. */ #include "wm.h" /* * Command definitions */ # define DUMPWINDOW 'd' /* dump contents of current window to file */ # define FITWINDOW 'f' /* Find best unobscured place for a window */ # define HELP2 'h' /* Command summary */ # define HELP1 '?' /* Command summary */ # define IDENTWINDOW 'i' /* print name of current window */ # define KILLWINDOW 'k' /* get rid of this window forever */ # define LASTWINDOW 'l' /* change to Last-used window */ # define MOVEWINDOW 'm' /* Move locn and/or change size of window */ # define NEWWINDOW 'n' /* make New window */ # define PREFIX 'p' /* change prefix character */ # define QUIT 'q' /* close up everything and Quit */ # define REDRAW 'r' /* Redraw all windows */ # define SAVEWINDOWS 's' /* save current window configuration */ # define TERMCAP 't' /* Reset $TERM and $TERMCAP of current window */ # define SUSPEND 'z' /* suspend wm */ # define NOOP1 ' ' /* no-op */ # define NOOP2 '\n' /* no-op */ # define NOOP3 '\r' /* no-op */ /* * Execute a WM command. */ docmd(cmd) int cmd; /* IN: command code */ { register int w, tmpw; int begline, begcol, lines, cols; /* window parameters */ char *s; register WINDOW *wp; switch (cmd) { case CANCEL1: case CANCEL2: showmsg("Canceled."); break; case NEWWINDOW: tmpw = topw; if ((w = GetSlot()) < 0) { showmsg("Sorry, can't create any more windows."); break; } if (NewWindow(w,LINES-1,COLS,0,0)) break; WListAdd(w); if (getbounds(w, TRUE) != 0) break; /* getbounds will have freed the window */ lastw = tmpw; showmsg("Created new window #%d.", w); winchanged(w); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': w = ctoi(cmd); if ( ! iswindow(w)) showmsg("No such window #%d.", w); else if (w == topw) showmsg("You're already in window #%d.", w); else { lastw = topw; WListDelete(w); WListAdd(w); RedrawScreen(); showmsg("Changed to window #%d.", w); } break; case LASTWINDOW: if (iswindow(lastw) && lastw!=topw) { w=lastw; lastw=topw; WListDelete(w); WListAdd(w); RedrawScreen(); showmsg("Changed back to window #%d.", w); } else showmsg("No last window."); break; case MOVEWINDOW: w = topw; wp = win[w].wptr; lines = wlines(wp); cols = wcols(wp); begline = wbegy(wp); begcol = wbegx(wp); if (getbounds(w, FALSE) != 0) break; wp = win[w].wptr; if (lines == wlines(wp) && cols == wcols(wp)) { if (begline == wbegy(wp) && begcol == wbegx(wp)) { showmsg("Window unchanged."); break; } } else SetTerm(w, 2); showmsg("Moved window #%d.", w); winchanged(w); break; case FITWINDOW: showmsg("Fit which window?"); if ((w = askwindow()) < 0) break; if (fitwindow(w, &lines, &cols, &begline, &begcol) < 0) { showmsg("Sorry, cannot find unobscured placement."); break; } wp = win[w].wptr; tmpw = 1; /* shameless misuse of variable */ if (lines == wlines(wp) && cols == wcols(wp)) { tmpw = 0; if (begline == wbegy(wp) && begcol == wbegx(wp)) { showmsg("Window already has best fit."); break; } } if (NewWindow(w,lines,cols,begline,begcol)) { WListDelete(w); break; } if (tmpw) SetTerm(w, 2); RedrawScreen(); showmsg("Moved window #%d.", w); winchanged(w); break; case KILLWINDOW: showmsg("Kill which window?"); /* enter window name */ if ((w = askwindow()) < 0) break; if (w==topw) { showmsg("Can't kill the current window."); break; } WListDelete(w); KillShell(w); FreeWindow(w); RedrawScreen(); showmsg("Killed window #%d.", w); if (w==lastw) lastw = -1; configflag = TRUE; break; case IDENTWINDOW: IdentWindows(); break; case DUMPWINDOW: if ((s = WPrompt("dump file", "wmdump")) == NULL) break; else if (DumpWindow(topw, s) == 0) showmsg("Dumped contents of top window to file '%s'.", s); else showmsg("Sorry, can't open dump file '%s'.", s); break; case REDRAW: ClearScreen(); RedrawScreen(); break; case TERMCAP: SetTerm(topw, 3); break; case HELP1: case HELP2: ClearScreen(); helpmsg(); (void) tty_getch(); ClearScreen(); RedrawScreen(); break; case PREFIX: showmsg("Enter new WM prefix character."); prefix = tty_getch(); showmsg("New WM prefix character is '%s'.", mkprint(prefix)); configflag = TRUE; break; case SUSPEND: suspend(); break; case SAVEWINDOWS: if ((s = WPrompt("save file", savefile)) == NULL) break; (void) strcpy(savefile, s); if (Save(savefile) != 0) { showmsg("Saved current window configuration in '%s'.", savefile); configflag = FALSE; } else showmsg("Sorry, can't save current window configuration."); break; case QUIT: return(TRUE); case NOOP1: case NOOP2: case NOOP3: break; default: showmsg("Invalid command '%s': use 'h' command for help.",mkprint(cmd)); break; } return(FALSE); } /* * suspend w/ job control if using csh, otherwise spawn subshell. * This could be integrated into curses tstp(), * but I wasn't sure that could be done correctly, * since it is impossible(?) to determine if the parent shell * knows job control. */ suspend() { register int rc; #ifndef TERMINFO register int ttyflags; #endif /* If wm's parent is init, then we better not suspend with TSTP! * Unfortunately, this heuristic fails if the user used rlogin, * since wm's parent would then be rlogind. We can only hope * the user knows what he is doing. */ if (getppid() != 1 && (rc = strlen(shellname)) >= 3 && strcmp(shellname+rc-3, "csh") == 0) { showmsg("Suspending."); tstp(); showmsg("WM resumed."); return; } showmsg("Spawning a sub-shell ..."); (void) movecursor(LINES-1, 0); #ifndef TERMINFO ttyflags = _tty.sg_flags; #endif endwin(); putchar('\n'); /* scroll up, for neatness */ (void) fflush(stdout); rc = system(shellpgm); #ifdef TERMINFO #ifdef BUGGYTERMINFO /* Alas, buggyterminfo apparently does not re-remember the virgin state * or correct for a baud-rate change */ #endif fixterm(); #else savetty(); /* re-remember the virgin state */ _tty.sg_flags = ttyflags; (void) ioctl(_tty_ch, TIOCSETN, (char *)&_tty); #endif if (enter_ca_mode) putp(enter_ca_mode); wrefresh(curscr); /* we could diagnose things better here */ if (rc == 127) showmsg("Cannot spawn a shell!"); else showmsg("Returning to WM."); } /* * Set 'configflag' to indicate change affecting wmrc file. * If this window is full-width or full-length, * set the corresponding 'flex' flag. * Warn user if this is a 'slow' window. */ winchanged(w) register int w; { register WINDOW *wp; static int full_width_warning = FALSE; configflag = TRUE; win[w].flags &= ~(XFLEX|YFLEX); wp = win[w].wptr; if (wcols(wp) == COLS) win[w].flags |= XFLEX; if (wlines(wp) == LINES-1) win[w].flags |= YFLEX; WObscure(); /* recompute obscured window info */ if (!(win[w].flags&FAST)) { if (wcols(wp) != COLS) { showmsg("\007Non full-width window #%d will scroll slowly!", w); return; } if (full_width_warning) return; full_width_warning = TRUE; showmsg("\007This terminal scrolls split-screen windows slowly."); } } SHAR_EOF if test 7983 -ne "`wc -c < 'cmd.c'`" then echo shar: error transmitting "'cmd.c'" '(should have been 7983 characters)' fi fi # end of overwriting check echo shar: extracting "'curses.c'" '(11058 characters)' if test -f 'curses.c' then echo shar: will not over-write existing file "'curses.c'" else sed 's/^X//' << \SHAR_EOF > 'curses.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. ************* */ /* * curses.c R. Jacob */ #include "wm.h" static WINDOW *mw=NULL; /* message window */ static WINDOW *cmw=NULL; /* blank message window */ time_t msgbirth = 0; /* * Set up win structure and associated junk for new window w. * Returns 0 if sucessful, else -1. */ NewWindow(w, lines, cols, begline, begcol) register int w; int lines, cols, begline, begcol; { register WINDOW *wp, *owp; if ((wp=newwin(lines,cols,begline,begcol)) == NULL) { showmsg("\007Cannot %sconstruct window #%d!.", ((win[w].flags&INUSE)? "re": ""), w); FreeWindow(w); return(-1); } leaveok(wp, TRUE); /* If the window is already in use, copy old window to new one * anchored at bottom left of the windows. * We move the bottom left of both windows to the bottom left * of the screen, overwrite, then move the windows back. * (Actually, we do not bother to move the old window back.) */ if (win[w].flags&INUSE) { owp = win[w].wptr; mvwin(owp, LINES-wlines(owp), 0); mvwin(wp, LINES-wlines(wp), 0); overwrite(owp, wp); mvwin(wp, begline, begcol); wmove(wp, wcury(owp) + (wlines(wp)-wlines(owp)), wcurx(owp)); FreeWindow(w); } win[w].wptr = wp; if (MakeBorders(w) != 0) { showmsg("\007Cannot construct borders for window #%d!.", w); FreeWindow(w); return(-1); } win[w].flags |= INUSE; if (has_scroll_window || (cols == COLS && (has_scroll_region || has_insdel_line || lines == LINES-1))) win[w].flags |= FAST; return(0); } /* * Deallocate win structure and associated junk. */ XFreeWindow(w) register int w; { win[w].flags = 0; if (win[w].wptr) {delwin(win[w].wptr); win[w].wptr = 0;} if (win[w].boxbot) {delwin(win[w].boxbot); win[w].boxbot = 0;} if (win[w].boxtop) {delwin(win[w].boxtop); win[w].boxtop = 0;} if (win[w].boxright) {delwin(win[w].boxright); win[w].boxright = 0;} if (win[w].boxleft) {delwin(win[w].boxleft); win[w].boxleft = 0;} } #ifdef notdef /* * Redraw window w. */ RedrawWindow(w) register int w; { register WINDOW *wp; if (!iswindow(w)) return; if (wp=win[w].wptr) { touchwin(wp); wrefresh(wp); } if (wp=win[w].boxbot) { touchwin(wp); wrefresh(wp); } if (wp=win[w].boxtop) { touchwin(wp); wrefresh(wp); } if (wp=win[w].boxright) { touchwin(wp); wrefresh(wp); } if (wp=win[w].boxleft) { touchwin(wp); wrefresh(wp); } } #endif /* * Redraw the entire screen. * Uses Curses' standard screen, stdscr. */ RedrawScreen() { register int w, base; register WINDOW *wp; /* speed hack: start with the topmost full-screen window. * (Smarter hacks come to mind, but this one is easy.) */ base = botw; for (w=base; w>=0; w=win[w].next) if ((wp = win[w].wptr) && wcols(wp) == COLS && wlines(wp) >= LINES-1) base = w; werase(stdscr); /* Write contents of all windows into stdscr, then refresh. */ for (w=base; w>=0; w=win[w].next) { if (wp=win[w].wptr) overwrite(wp, stdscr); if (wp=win[w].boxtop) overwrite(wp, stdscr); if (wp=win[w].boxbot) overwrite(wp, stdscr); if (wp=win[w].boxright) overwrite(wp, stdscr); if (wp=win[w].boxleft) overwrite(wp, stdscr); } if (msgbirth) overwrite(mw, stdscr); touchwin(stdscr); wrefresh(stdscr); RestoreCursor(); } /* * Identify windows. * Draw each window in turn, from bottom to top. * Uses Curses' standard screen, stdscr. */ IdentWindows() { register int w; /* window index */ register WINDOW *wp; register int canceled=FALSE; /* TRUE if user cancels this command */ register int c; /* Erase the screen (and stdscr). */ ClearScreen(); /* Write contents of each window into stdscr, then refresh. */ for (w=botw; w>=0; w=win[w].next) { if (wp=win[w].wptr) overwrite(wp, stdscr); if (wp=win[w].boxtop) overwrite(wp, stdscr); if (wp=win[w].boxbot) overwrite(wp, stdscr); if (wp=win[w].boxright) overwrite(wp, stdscr); if (wp=win[w].boxleft) overwrite(wp, stdscr); if (canceled) continue; #ifdef BUGGYTERMINFO /* buggyterminfo seems to require this */ touchwin(stdscr); #endif wrefresh(stdscr); if (w != topw) { showmsg("Window #%d. Hit any key to see next window.", w); c = tty_getch(); if (c == CANCEL1 || c == CANCEL2) { showmsg("Canceled."); canceled = TRUE; } } else { showmsg("Window #%d (top window). Hit any key to continue.", w); (void) tty_getch(); } } if (canceled) wrefresh(stdscr); RestoreMsg(); RestoreCursor(); } /* * Show message s on bottom of screen. */ /*VARARGS1*/ showmsg(s, arg1, arg2) register char *s; { char buf[256]; /* Initialize message window first time 'round. */ if (mw == NULL) { mw=newwin(1, 0, LINES-1, 0); cmw=newwin(1, 0, LINES-1, 0); if (!mw || !cmw) { fprintf(stderr, "Cannot create message window!\n\r"); Shutdown(1); } leaveok(cmw, TRUE); werase(cmw); /* (leaveok for mw & cursor positioning for prompts needs thought) */ wstandout(mw); } #ifdef notdef /* pause to let user ponder a previous message */ if (msgbirth && *s && (t = 2-abs(msgbirth - time((time_t *)0))) > 0) sleep((unsigned int)t); #endif /* Format the message */ (void) sprintf(buf, s, arg1, arg2); s = buf; s[wcols(mw)-1] = '\0'; /* make sure it fits */ /* hack to honk but once */ if (*s == '\007') { flash(); s++; } werase(mw); waddstr(mw, s); touchwin(mw); wrefresh(mw); msgbirth = s[0]? time((time_t *)0): 0; } ZapMsgLine() { if (msgbirth) { touchwin(cmw); wrefresh(cmw); } } RestoreMsg() { if (msgbirth) { touchwin(mw); wrefresh(mw); } } /* * Restore cursor in top window. */ RestoreCursor() { register WINDOW *wp; /* pointer to top window */ wp = win[topw].wptr; if (movecursor(wbegy(wp)+wcury(wp), wbegx(wp)+wcurx(wp))) (void) fflush(stdout); } /* * Clear the whole screen */ ClearScreen() { wclear(stdscr); wrefresh(stdscr); } /* * Creates windows containing * a border to surround window w * and puts pointer to the new windows * into proper places in global win[]. * Borders appear in standout mode if * terminal has that capability. * Returns 0 if sucessful, else -1. */ MakeBorders(w) register int w; /* make borders for this window */ { int left, right, top, bottom; /* border flags */ int begx, begy, cols, lines; /* window dimensions */ register WINDOW *wp; /* window pointer */ register int i; /* index */ /* Get window dimensions. */ wp = win[w].wptr; begx = wbegx(wp); begy = wbegy(wp); cols = wcols(wp); lines = wlines(wp); /* Determine which sides of the window need borders. */ left = (begx > 0); right = (begx+cols < COLS); top = (begy > 0); bottom = (begy+lines < LINES-1); /* bottom line for msgs */ if (top) --begy, ++lines; if (bottom) lines++; /* Make left border using '>'. */ if (left) { if ((win[w].boxleft = wp = newwin(lines,1,begy,begx-1)) == NULL) return(-1); leaveok(wp, TRUE); wstandout(wp); for (i=0; i'); } /* Make right border using '<'. */ if (right) { if ((win[w].boxright = wp = newwin(lines,1,begy,begx+cols)) == NULL) return(-1); leaveok(wp, TRUE); wstandout(wp); for (i=0; i= 0) if (toascii(mvwinch(wp, line, lastcol)) != ' ') break; for (col = 0; col <= lastcol; col++) putc(toascii(mvwinch(wp, line, col)), dfp); putc('\n', dfp); } (void) fclose(dfp); wmove(wp, oldy, oldx); return(0); } #define BUFLEN 80 /* Prompt user for a string. */ char * WPrompt(prompt, dflt) char *prompt; /* prompt */ char *dflt; /* default response */ { register int c; /* character in string */ static char buf[BUFLEN+1]; /* string buffer */ register int i=0; /* buffer index */ int maxlen, x; /* how long can string be? */ /* Print prompt and default response * on bottom line of screen. */ showmsg("%s? [%s] ", prompt, dflt); /* Determine length of longest string * that will fit in window. */ x = wcurx(mw); maxlen = (BUFLEN < wcols(mw)-2-x ? BUFLEN : wcols(mw)-2-x); /* Read string. Process line kill & backspace chars. */ while ((c = tty_getch()) != EOF && c != '\n' && c != '\r') { if (c==CANCEL1 || c==CANCEL2) /* cancel */ { showmsg("Canceled."); return(NULL); } if (c==erasechar() || c == KEY_BACKSPACE || c == KEY_LEFT) { if (i > 0) { i--; waddstr(mw, "\b \b"); } } else if (c == killchar()) { i = 0; wmove(mw, 0, x); wclrtoeol(mw); } else if (i > maxlen) /* is string too long? */ flash(); else if (isspace(c) || !isprint(c)) /* is character inappropriate? */ flash(); else /* regular char: add to string */ { waddch(mw, c); buf[i++] = c; } wrefresh(mw); } /* If user didn't respond, just return default response. */ if (i == 0) strcpy(buf, dflt); else buf[i] = '\0'; return(buf); } SHAR_EOF if test 11058 -ne "`wc -c < 'curses.c'`" then echo shar: error transmitting "'curses.c'" '(should have been 11058 characters)' fi fi # end of overwriting check echo shar: extracting "'getch.c'" '(6283 characters)' if test -f 'getch.c' then echo shar: will not over-write existing file "'getch.c'" else sed 's/^X//' << \SHAR_EOF > 'getch.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. ************* */ #include "wm.h" #include char keycap[200]; /* termcap entries for keypad functions */ int tty_backcnt; /* number of pre-read terminal chars */ char tty_backbuf[10]; /* stack of pre-read chars */ char tty_text[10]; /* actual text corresponding to tty_getch code */ int tty_textlen; /* strlen(tty_text) */ /* * Returns true iff a call to tty_realgetch would not block. */ tty_inputpending() { long n; if (tty_backcnt > 0) return(TRUE); if (ioctl(0, (int)FIONREAD, (char *)&n) == 0 && n > 0) return(TRUE); return(FALSE); } /* * Read the next character from the terminal (or the backbuf), * return EOF if end of file, else (int)the_char, sans parity */ int tty_realgetch() { char c; if (tty_backcnt > 0) c = tty_backbuf[--tty_backcnt]; else if (read(0, &c, 1) <= 0) { tty_text[0] = '\0'; tty_textlen = 0; return(EOF); } c = toascii(c); tty_text[0] = c; tty_text[1] = '\0'; tty_textlen = 1; return(c); } #ifdef GAGMEKEYPAD init_keypad() { register int i; register char *p; char buf1[10]; if (p = getcap("ks")) putp(p); for (i=1,p = "kbkukdklkrkhk0k1k2k3k4k5k6k7k8k9"; *p; i++,p+= 2) { (void) sprintf(buf1, "%2.2s", p); add_to_try(buf1, i+0400); } } /* ** add_to_try() (Copyright Pavel Curtis, see notice in hacks.c) ** ** Construct the try for the current terminal's keypad keys. ** */ struct try { struct try *child; /* ptr to child. NULL if none */ struct try *sibling; /* ptr to sibling. NULL if none */ char ch; /* character at this node */ short value; /* code of string so far. NULL if none */ }; static struct try *newtry; add_to_try(capname, code) char *capname; int code; { register struct try *ptr, *savedptr; register char *str, *s; static bool out_of_memory = FALSE; str = getcap(capname); if (! str || out_of_memory) return; strcat(keycap, capname); strcat(keycap, "="); for (s = str; *s; s++) { strcat(keycap, mkprint(*s)); } strcat(keycap, ":"); if (newtry != NULL) { ptr = newtry; for (;;) { while (ptr->ch != *str && ptr->sibling != NULL) ptr = ptr->sibling; if (ptr->ch == *str) { if (*(++str)) { if (ptr->child != NULL) ptr = ptr->child; else break; } else { ptr->value = code; return; } } else { if ((ptr->sibling = alloc(1, struct try)) == NULL) { out_of_memory = TRUE; return; } savedptr = ptr = ptr->sibling; ptr->child = ptr->sibling = NULL; ptr->ch = *str++; ptr->value = NULL; break; } } /* end for (;;) */ } else /* newtry == NULL :: First sequence to be added */ { savedptr = ptr = newtry = alloc(1, struct try); if (ptr == NULL) { out_of_memory = TRUE; return; } ptr->child = ptr->sibling = NULL; ptr->ch = *(str++); ptr->value = NULL; } /* at this point, we are adding to the try. ptr->child == NULL */ while (*str) { ptr->child = alloc(1, struct try); ptr = ptr->child; if (ptr == NULL) { out_of_memory = TRUE; ptr = savedptr; while (ptr != NULL) { savedptr = ptr->child; free((char *)ptr); ptr = savedptr; } return; } ptr->child = ptr->sibling = NULL; ptr->ch = *(str++); ptr->value = NULL; } ptr->value = code; return; } #include static jmp_buf jmpbuf; /* ** tty_getch() (Copyright Pavel Curtis, see notice in hacks.c) ** ** Get an input character, but take care of keypad sequences, returning ** an appropriate code when one matches the input. After each character ** is received, set an alarm call. If no more of the sequence ** is received by the time the alarm goes off, pass through the sequence ** gotten so far. ** */ tty_getch() { /* longjmp alert! beware of register variables */ register struct try *ptr; int ch; char buffer[10]; /* Assume no sequences longer than 10 */ char *bufp = buffer; int (*oldsigalrm)(); int sigalrm(); bool alarmset; ptr = newtry; alarmset = FALSE; oldsigalrm = SIG_DFL; /* to quiet lint */ do { if (setjmp(jmpbuf)) break; ch = tty_realgetch(); if (ch != EOF) /* returns EOF on error, too */ *(bufp++) = ch; while (ptr != NULL && ptr->ch != ch) ptr = ptr->sibling; if (ptr != NULL) { if (ptr->value != NULL) { if (alarmset) { (void) ualarm(0L); (void) signal(SIGALRM, oldsigalrm); } tty_textlen = bufp-buffer; bcopy(buffer, tty_text, tty_textlen); return(ptr->value); } else { ptr = ptr->child; if (!alarmset) { alarmset = TRUE; oldsigalrm = signal(SIGALRM, sigalrm); } (void) ualarm(200000L); } } } while (ptr != NULL); if (alarmset) { (void) ualarm(0L); (void) signal(SIGALRM, oldsigalrm); } if (bufp <= buffer) return(EOF); while (--bufp > buffer) tty_backbuf[tty_backcnt++] = *bufp; return(*bufp); } static sigalrm() { longjmp(jmpbuf, 1); } /* * ualarm(usec). If this doesn't compile, just use alarm(0) and alarm(1). */ #include #define MILLION 1000000L ualarm(usecs) long usecs; { struct itimerval it, oitv; register struct itimerval *itp = ⁢ timerclear(&itp->it_interval); itp->it_value.tv_sec = usecs/MILLION; itp->it_value.tv_usec = usecs%MILLION; if (setitimer(ITIMER_REAL, itp, &oitv) < 0) return (-1); return (oitv.it_value.tv_sec*MILLION+oitv.it_value.tv_usec); } #endif SHAR_EOF if test 6283 -ne "`wc -c < 'getch.c'`" then echo shar: error transmitting "'getch.c'" '(should have been 6283 characters)' fi fi # end of overwriting check echo shar: extracting "'hacks.c'" '(11742 characters)' if test -f 'hacks.c' then echo shar: will not over-write existing file "'hacks.c'" else sed 's/^X//' << \SHAR_EOF > 'hacks.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. ************* */ /* * hacks.c * curses-package routines missing in one version or another, * or corrections for routines in one version or another, * or whatever. */ #include "wm.h" /* * Special redefinitions. We get right into the dirt here. */ #ifndef TERMINFO #define _line _y #define chtype char #define _firstchar _firstch #define _lastchar _lastch #endif /* * Move physical cursor to (y,x). * If y is past the end of the screen, scroll the screen up. * This is an ugly routine in either version of curses, * perhaps because no one worried about this sort of thing. * (It would be nice to be able to request 'anywhere on line y', * or 'anywhere in column x', since more optimizations are then possible.) */ movecursor(y,x) register int y, x; { if (cursrow() == y && curscol() == x) return(0); #ifdef TERMINFO if (y >= LINES) { (void) movecursor(y-1,x); vidattr(A_NORMAL); putp(scroll_forward); return(1); } Untouchwin(stdscr); leaveok(stdscr, FALSE); wmove(stdscr, y, x); wrefresh(stdscr); leaveok(stdscr, TRUE); #else /* Couldn't mvcur handle the move_standout_mode problem? */ if ((curscr->_flags&_STANDOUT) && !move_standout_mode) { putp(exit_standout_mode); curscr->_flags &= ~_STANDOUT; } /* speed hack: short circuit mvcur for simple scrolling */ if (y == LINES && curscol() == x && cursrow()+2 == y && cursor_down) { putp(cursor_down); putp(scroll_forward); } else mvcur(cursrow(), curscol(), y, x); /* Couldn't mvcur update curscr's current (y,x) coordinate? */ if (y >= LINES) y = LINES-1; cursrow() = y; curscol() = x; #endif return(1); } /* * Make it appear that every location on the window is unchanged. */ untouchwin(wp) register WINDOW *wp; { register int i; for (i=0; i_firstchar[i] = _NOCHANGE; #ifdef TERMINFO wp->_lastchar[i] = _NOCHANGE; wp->_numchngd[i] = 0; #endif } } /* * This is a replacement overwrite() routine for both curses versions. * The termcap version is slow and has some minor bugs. * The terminfo version aligns the two windows at their origins, * rather than on the virtual screen, making it less useful * as one cannot use 'mvwin' &etc to paint one window at an * arbitrary place on another. * Neither version documents what is done with 'standout' information. * This version copies the standout information for each character * so that a truly identical copy is made, which is handy for painting. */ /********************************************************************* * COPYRIGHT NOTICE * ********************************************************************** * This software is copyright (C) 1982 by Pavel Curtis * * * * Permission is granted to reproduce and distribute * * this file by any means so long as no fee is charged * * above a nominal handling fee and so long as this * * notice is always included in the copies. * * * * Other rights are reserved except as explicitly granted * * by written permission of the author. * * Pavel Curtis * * Computer Science Dept. * * 405 Upson Hall * * Cornell University * * Ithaca, NY 14853 * * * * Ph- (607) 256-4934 * * * * Pavel.Cornell@Udel-Relay (ARPAnet) * * decvax!cornell!pavel (UUCPnet) * *********************************************************************/ /* ** ** overwrite(win1, win2) ** ** ** overwrite() writes win1 on win2 destructively. ** **/ overwrite(win1, win2) WINDOW *win1, *win2; { register chtype *w1ptr, *w2ptr; register int col, end_col; int line, offset_line, offset_col, start_line, start_col, end_line; short *firstchar, *lastchar; #ifdef TRACE if (_tracing) _tracef("overwrite(%o, %o) called", win1, win2); #endif offset_line = wbegy(win1) - wbegy(win2); offset_col = wbegx(win1) - wbegx(win2); start_line = MAX(offset_line, 0); start_col = MAX(offset_col, 0); end_line = offset_line + wlines(win1) - wlines(win2); end_line = wlines(win2) + MIN(end_line, 0); end_col = offset_col + wcols(win1) - wcols(win2); end_col = wcols(win2) + MIN(end_col, 0); firstchar = &win2->_firstchar[start_line]; lastchar = &win2->_lastchar[start_line]; for(line = start_line; line < end_line; line++) { short fc, lc; w1ptr = &win1->_line[line-offset_line][start_col-offset_col]; w2ptr = &win2->_line[line][start_col]; fc = lc = _NOCHANGE; for(col = start_col; col < end_col; col++) { if (*w1ptr != *w2ptr) { *w2ptr = *w1ptr; if (fc == _NOCHANGE) fc = col; lc = col; } w1ptr++; w2ptr++; } if (*firstchar == _NOCHANGE) { *firstchar = fc; *lastchar = lc; } else if (fc != _NOCHANGE) { if (fc < *firstchar) *firstchar = fc; if (lc > *lastchar) *lastchar = lc; } firstchar++; lastchar++; } } #ifndef TERMINFO /* * Emulators for terminfo curses procedures. */ #ifdef SET_WINDOW /* * tparm.c (Copyright Pavel Curtis, copyright notice above applies) */ /* * char * * tparm(string, parms) * * Substitute the given parameters into the given string. */ #define STACKSIZE 20 #define npush(x) if (stack_ptr < STACKSIZE) {stack[stack_ptr].num = x;\ stack_ptr++;\ } #define npop() (stack_ptr > 0 ? stack[--stack_ptr].num : 0) #define spop() (stack_ptr > 0 ? stack[--stack_ptr].str : (char *) 0) typedef union { unsigned int num; char *str; } stack_frame; stack_frame stack[STACKSIZE]; static int stack_ptr; static char buffer[256]; static int *param; static char *bufptr; static int variable[26]; /*VARARGS1*/ char * tparm(string, parms) char *string; int parms; { char len; int number; int level; int x, y; param = &parms; stack_ptr = 0; bufptr = buffer; while (*string) { if (*string != '%') *(bufptr++) = *string; else { string++; switch (*string) { default: break; case '%': *(bufptr++) = '%'; break; case 'd': (void) sprintf(bufptr, "%d", npop()); bufptr += strlen(bufptr); break; case '0': string++; len = *string; if ((len == '2' || len == '3') && *++string == 'd') { if (len == '2') (void) sprintf(bufptr, "%02d", npop()); else (void) sprintf(bufptr, "%03d", npop()); bufptr += strlen(bufptr); } break; case '2': string++; if (*string == 'd') { (void) sprintf(bufptr, "%2d", npop()); bufptr += strlen(bufptr); } break; case '3': string++; if (*string == 'd') { (void) sprintf(bufptr, "%3d", npop()); bufptr += strlen(bufptr); } break; case 'c': *(bufptr++) = (char) npop(); break; case 's': strcpy(bufptr, spop()); bufptr += strlen(bufptr); break; case 'p': string++; if (*string >= '1' && *string <= '9') npush(param[*string - '1']); break; case 'P': string++; if (*string >= 'a' && *string <= 'z') variable[*string - 'a'] = npop(); break; case 'g': string++; if (*string >= 'a' && *string <= 'z') npush(variable[*string - 'a']); break; case '\'': string++; npush(*string); string++; break; case '{': number = 0; string++; while (*string >= '0' && *string <= '9') { number = number * 10 + *string - '0'; string++; } npush(number); break; case '+': y = npop(); x = npop(); npush(x + y); break; case '-': y = npop(); x = npop(); npush(x - y); break; case '*': y = npop(); x = npop(); npush(x * y); break; case '/': y = npop(); x = npop(); npush(x / y); break; case 'm': y = npop(); x = npop(); npush(x % y); break; case '&': y = npop(); x = npop(); npush(x & y); break; case '|': y = npop(); x = npop(); npush(x | y); break; case '^': y = npop(); x = npop(); npush(x ^ y); break; case '=': y = npop(); x = npop(); npush(x == y); break; case '<': y = npop(); x = npop(); npush(x < y); break; case '>': y = npop(); x = npop(); npush(x > y); break; case '!': x = npop(); npush(! x); break; case '~': x = npop(); npush(~ x); break; case 'i': param[0]++; param[1]++; break; case '?': break; case 't': x = npop(); if (x) { /* do nothing; keep executing */ } else { /* scan forward for %e or %; at level zero */ string++; level = 0; while (*string) { if (*string == '%') { string++; if (*string == '?') level++; else if (*string == ';') { if (level > 0) level--; else break; } else if (*string == 'e' && level == 0) break; } if (*string) string++; } } break; case 'e': /* scan forward for a %; at level zero */ string++; level = 0; while (*string) { if (*string == '%') { string++; if (*string == '?') level++; else if (*string == ';') { if (level > 0) level--; else break; } } if (*string) string++; } break; case ';': break; } /* endswitch (*string) */ } /* endelse (*string == '%') */ if (*string == '\0') break; string++; } /* endwhile (*string) */ *bufptr = '\0'; return(buffer); } #endif /* * Ring Bell. */ beep() { putchar('\007'); } /* * 'Ring' visual bell if available, otherwise audible bell. */ flash() { /* If you get a syntax error on this routine, * you are not using the new curses.h! Put * it in this directory or in /usr/include (saving the old one). * And double check that you are linking with the new libcurses.a */ if (flash_screen) putp(flash_screen); else beep(); } /* * Return the baud rate of the current terminal. */ baudrate() { #ifdef B9600 if (_tty.sg_ospeed >= B9600) return(9600); #endif #ifdef B4800 if (_tty.sg_ospeed >= B4800) return(4800); #endif return(1200); } erasechar() { return(_tty.sg_erase); } killchar() { return(_tty.sg_kill); } #endif SHAR_EOF if test 11742 -ne "`wc -c < 'hacks.c'`" then echo shar: error transmitting "'hacks.c'" '(should have been 11742 characters)' fi fi # end of overwriting check echo shar: extracting "'help.c'" '(2137 characters)' if test -f 'help.c' then echo shar: will not over-write existing file "'help.c'" else sed 's/^X//' << \SHAR_EOF > 'help.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. ************* */ #include "wm.h" /* * print a command summary over the top of the screen, then redraw */ helpmsg() { printf("Code Command Description\r\n"); printf("---- ------- -----------\r\n"); printf("%d..%d change Change to the named window\r\n", MINWINDOW, MAXWINDOWS-1); printf("d dump dump current window contents to a file\r\n"); printf("h or ? help print this help message\r\n"); printf("i identify identify windows\r\n"); printf("k kill kill a window permanently\r\n"); printf("l last change to last-used window\r\n"); printf("m move move and/or change size of current window\r\n"); printf("n new make a new window\r\n"); printf("p prefix change WM prefix character (See EXECUTE below)\r\n"); printf("q quit quit WM\r\n"); printf("r redraw redraw entire screen\r\n"); printf("s save save current window configuration\r\n"); printf("t termcap reset $TERM and $TERMCAP of current window\r\n"); printf("z suspend suspend WM (or spawn non-window subshell)\r\n"); printf("----------------------------------------------------------\r\n"); printf("To EXECUTE a command, type the WM prefix character (%s) then the command code.\r\n", mkprint(prefix)); printf("To ENTER the prefix character itself, type it twice.\r\n"); printf("To CANCEL a WM command before it executes, type or .\r\n"); printf("For FUTHER INFORMATION, consult the 'wm' manual entry.\r\n"); printf("------------------------------\r\n"); printf("Now hit any key to return to WM"); (void)fflush(stdout); } SHAR_EOF if test 2137 -ne "`wc -c < 'help.c'`" then echo shar: error transmitting "'help.c'" '(should have been 2137 characters)' fi fi # end of overwriting check # End of shell archive exit 0