home *** CD-ROM | disk | FTP | other *** search
- From: guido@cwi.nl (Guido van Rossum)
- Newsgroups: alt.sources
- Subject: STDWIN 0.9.5, Part 04/19
- Message-ID: <3068@charon.cwi.nl>
- Date: 4 Mar 91 11:57:42 GMT
-
- Archive-name: stdwin/part04
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 4 (of 19)."
- # Contents: Appls/test/test1.c Packs/vt/vt.c Ports/x11/window.c
- # Wrapped by guido@voorn.cwi.nl on Mon Mar 4 12:37:24 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'Appls/test/test1.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Appls/test/test1.c'\"
- else
- echo shar: Extracting \"'Appls/test/test1.c'\" \(251 characters\)
- sed "s/^X//" >'Appls/test/test1.c' <<'END_OF_FILE'
- X/* Basic test -- open and close a window; no output or events. */
- X
- X#include "stdwin.h"
- X
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X{
- X WINDOW *win;
- X winitargs(&argc, &argv);
- X win= wopen("Basic test", (void (*)()) 0);
- X wclose(win);
- X wdone();
- X exit(0);
- X}
- END_OF_FILE
- if test 251 -ne `wc -c <'Appls/test/test1.c'`; then
- echo shar: \"'Appls/test/test1.c'\" unpacked with wrong size!
- fi
- # end of 'Appls/test/test1.c'
- fi
- if test -f 'Packs/vt/vt.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Packs/vt/vt.c'\"
- else
- echo shar: Extracting \"'Packs/vt/vt.c'\" \(20134 characters\)
- sed "s/^X//" >'Packs/vt/vt.c' <<'END_OF_FILE'
- X/* Virtual Terminal -- basic output routines */
- X
- X#include "vtimpl.h"
- X
- X#ifdef macintosh
- X/* Bold mode uses the "Bold" font, found in VersaTerm;
- X this matches Monaco and is available only in 9 pt. */
- X#define DO_BOLD
- X#define SETBOLD() wsetfont("Bold")
- X#define SETNORMAL() wsetfont("Monaco")
- X#endif
- X
- X/* Forward */
- XSTATIC void vtdrawproc _ARGS((WINDOW *win,
- X int left, int top, int right, int bottom));
- XSTATIC void vtdraw _ARGS((VT *vt, int r1, int c1, int r2, int c2));
- XSTATIC void vtchrange _ARGS((VT *vt, int r1, int c1, int r2, int c2));
- X
- X/* Administration for vtfind */
- X
- Xstatic VT **vtlist; /* Registered VT structs */
- Xstatic int nvt; /* Number of registered VT structs */
- X
- X/* Open a VT window of given size */
- X
- XVT *
- Xvtopen(title, rows, cols, save)
- X char *title;
- X int rows, cols;
- X int save; /* Number of rows scroll-back capacity */
- X{
- X int row;
- X VT *vt = ALLOC(VT);
- X
- X if (vt == NULL)
- X return NULL;
- X rows += save; /* Documentsize: cols * (rows + scrollback) */
- X vt->rows = rows;
- X vt->cols = cols;
- X vt->topterm = save;
- X vt->cwidth = wcharwidth('0');
- X vt->cheight = wlineheight();
- X
- X vt->llen = NALLOC(short, rows);
- X vt->data = NALLOC(char *, rows);
- X vt->flags = NALLOC(unsigned char *, rows);
- X for (row = 0; row < rows; ++row) {
- X if (vt->data != NULL)
- X vt->data[row] = NALLOC(char, cols);
- X if (vt->flags != NULL)
- X vt->flags[row] = NALLOC(unsigned char, cols);
- X }
- X /* Assume that if one NALLOC fails, all following ones
- X for the same size also fail... */
- X if (vt->llen == NULL ||
- X vt->data == NULL ||
- X vt->data[rows-1] == NULL ||
- X vt->flags == NULL ||
- X vt->flags[rows-1] == NULL) {
- X vt->win = NULL;
- X vtclose(vt);
- X return NULL;
- X }
- X
- X vt->win = wopen(title, vtdrawproc);
- X if (vt->win == NULL) {
- X vtclose(vt);
- X return NULL;
- X }
- X
- X wsetdocsize(vt->win, cols * vt->cwidth, rows * vt->cheight);
- X wsetwincursor(vt->win, wfetchcursor("ibeam"));
- X
- X vt->nlcr = FALSE;
- X vt->drawing = FALSE;
- X vtreset(vt); /* Clear additional fields */
- X L_APPEND(nvt, vtlist, VT *, vt);
- X
- X return vt;
- X}
- X
- X/* Close a VT window.
- X Also used to clean-up when vtopen failed half-way */
- X
- Xvoid
- Xvtclose(vt)
- X VT *vt;
- X{
- X int i, row;
- X
- X for (i = 0; i < nvt; ++i) {
- X if (vt == vtlist[i]) {
- X L_REMOVE(nvt, vtlist, VT *, i);
- X break;
- X }
- X }
- X
- X if (vt->win != NULL)
- X wclose(vt->win);
- X for (row = 0; row < vt->rows; ++row) {
- X if (vt->data != NULL)
- X FREE(vt->data[row]);
- X if (vt->flags != NULL)
- X FREE(vt->flags[row]);
- X }
- X FREE(vt->data);
- X FREE(vt->flags);
- X FREE(vt);
- X}
- X
- X/* Output a string to a VT window.
- X This does not do escape sequence parsing or control character
- X interpretation, but honors the 'modes' the VT can be in
- X (insert, inverse/underline etc.) and the scrolling region.
- X It updates the cursor position and scrolls if necessary.
- X Note that after one or more calls to vtputstring it is necessary
- X to call vtsync(vt)! */
- X
- Xvoid
- Xvtputstring(vt, text, len)
- X VT *vt;
- X char *text;
- X int len;
- X{
- X int row = vt->cur_row;
- X int col = vt->cur_col;
- X short *llen = vt->llen;
- X int scr_top = (vt->scr_top == vt->topterm) ? 0 : vt->scr_top;
- X int scr_bot = (vt->cur_row >= vt->scr_bot) ? vt->rows : vt->scr_bot;
- X int wrap = 0; /* Number of times wrapped around */
- X int last_drawn_col;
- X
- X#ifndef NDEBUG
- X if (scr_top < 0 || scr_top > vt->rows) {
- X fprintf(stderr, "vtputstring: scr_top = %d\n", scr_top);
- X vtpanic("vtputstring bad scr_top");
- X }
- X
- X if (scr_bot < 0 || scr_bot > vt->rows) {
- X fprintf(stderr, "vtputstring: scr_bot = %d\n", scr_bot);
- X vtpanic("vtputstring bad scr_bot");
- X }
- X#endif
- X
- X /* Compute text length if necessary */
- X if (len < 0)
- X len = strlen(text);
- X
- X /* This is a 'do' loop so that a call with an empty
- X string will still normalize the cursor position */
- X
- X /* XXX This loop is 100 lines long! Sorry. */
- X
- X do {
- X int llen_row, n, oldcol;
- X
- X /* Normalize the cursor position.
- X When we get past the bottom edge we must scroll,
- X but the actual scrolling is delayed until later:
- X here we just wrap around and remember how many
- X times we've wrapped.
- X Thus, scrolling multiple lines is effected as
- X a 'jump' scroll up -- not so nice-looking,
- X but essential with current performance limitations
- X of bitblit hardware.
- X When faster machines become available we may need
- X an option to turn this optimization off in favour
- X of smooth scrolling. */
- X
- X if (col >= vt->cols) {
- X col = 0;
- X ++row;
- X if (wrap > 0 && row < scr_bot)
- X llen[row] = 0; /* Clear line */
- X }
- X if (row >= scr_bot) {
- X /* Should be able to turn this off? */
- X if (wrap == 0) last_drawn_col = col;
- X ++wrap;
- X row = scr_top;
- X llen[row] = 0;
- X }
- X oldcol = col; /* For vtdraw call below */
- X
- X /* If the cursor is beyond the current line length,
- X eg because of cursor positioning, pad with space.
- X Set llen_row to the new line length. */
- X llen_row = llen[row];
- X if (llen_row < col) {
- X do {
- X vt->data[row][llen_row] = ' ';
- X vt->flags[row][llen_row] = 0;
- X } while (++llen_row < col);
- X }
- X
- X /* Set n to the number of characters that can be
- X inserted in the current line */
- X n = vt->cols - col;
- X CLIPMAX(n, len);
- X
- X /* When inserting, shift the rest of the line right.
- X The last characters may fall of the edge. */
- X if (vt->insert && llen_row > col && col+n < vt->cols) {
- X int k;
- X llen_row += n;
- X CLIPMAX(llen_row, vt->cols);
- X vtscroll(vt, row, col, row+1, llen_row, 0, n);
- X for (k = llen_row - n; --k >= col; ) {
- X vt->data[row][k+n] = vt->data[row][k];
- X vt->flags[row][k+n] = vt->flags[row][k];
- X }
- X }
- X
- X /* Copy the characters into the line data */
- X#ifndef NDEBUG
- X if (col + n > vt->cols || row >= vt->rows) {
- X fprintf(stderr, "col=%d, n=%d, row=%d\n", col,n,row);
- X vtpanic("Bad index in vtputstring");
- X }
- X#endif
- X strncpy(vt->data[row] + col, text, n);
- X
- X /* Update loop administration, maintaining the invariant:
- X 'len' characters starting at 'text' still to do */
- X len -= n;
- X text += n;
- X
- X /* Set the corresponding flag bits.
- X The current column is set as a side effect. */
- X while (--n >= 0)
- X vt->flags[row][col++] = vt->gflags;
- X
- X /* Update line length */
- X CLIPMIN(llen_row, col);
- X llen[row] = llen_row;
- X
- X /* Maybe draw the characters now */
- X if (vt->lazy) {
- X D( printf("vtputstring: ") );
- X vtchrange(vt, row, oldcol, row, col);
- X }
- X else if (wrap == 0) {
- X VTBEGINDRAWING(vt);
- X werase(oldcol*vt->cwidth, row*vt->cheight,
- X col*vt->cwidth, (row+1)*vt->cheight);
- X
- X D( printf("vtputstring: ") );
- X last_drawn_col = col;
- X vtdraw(vt, row, oldcol, row + 1, col);
- X }
- X
- X /* Loop while more work to do */
- X
- X } while (len > 0);
- X
- X#if 0
- X /* XXX Why not? */
- X vtsetcursor(vt, row, col);
- X#endif
- X
- X /* Process delayed scrolling. */
- X
- X if (wrap > 0) {
- X /* Yes, we need to scroll.
- X When wrap > 1, we have scrolled more than a screenful;
- X then the vtscroll call is skipped, but we must still
- X circulate the lines internally. */
- X
- X /* Picture:
- X
- X scr_top ___________________ (first line affected)
- X . ___________________
- X . ______ row ________
- X . ___________________ (last line affected)
- X scr_bot
- X
- X Data move: circulate down so that the data at row
- X moves to scr_bot - 1.
- X Screen bits move: the line below row must
- X become scr_top.
- X We must also invalidate the characters changed
- X before we started scrolling, but we must do this
- X after the vtscroll call, because some STDWIN
- X versions don't properly scroll invalidated bits.
- X */
- X
- X if (row + 1 != scr_bot) vtcirculate(vt,
- X scr_top, scr_bot,
- X scr_bot - (row + 1));
- X if (wrap == 1) {
- X int n = (row + 1) - scr_top;
- X D( printf("Wrapped once; n=%d\n", n) );
- X vtscroll(vt, scr_top, 0, scr_bot, vt->cols, -n, 0);
- X if (!vt->lazy)
- X vtdraw(vt, scr_bot - n, last_drawn_col,
- X scr_bot, vt->cols);
- X }
- X else { /* Scrolled more than the scrolling region */
- X D( printf("Whole scrolling region: ") );
- X if (!vt->lazy)
- X vtdraw(vt, scr_top, 0, scr_bot, vt->cols);
- X }
- X row = scr_bot - 1;
- X }
- X
- X /* Set the new cursor position */
- X vtsetcursor(vt, row, col);
- X}
- X
- X/* Subroutine to invalidate the text range from (r1, c1) to (r2, c2).
- X This is not the same as vtchange; this function deals with text
- X ranges, while vtchange deals with rectangles. */
- X
- XSTATIC void
- Xvtchrange(vt, r1, c1, r2, c2)
- X VT *vt;
- X{
- X D( printf("vtchrange [%d,%d]~[%d,%d]\n", c1, r1, c2, r2) );
- X if (c1 >= vt->cols) {
- X MON_EVENT("vtchrange: c1 >= vt->cols");
- X ++r1; c1 = 0;
- X }
- X if (r1 >= r2) {
- X vtchange(vt, r1, c1, r2+1, c2);
- X }
- X else {
- X vtchange(vt, r1, c1, r1+1, vt->cols);
- X vtchange(vt, r1+1, 0, r2, vt->cols);
- X vtchange(vt, r2, 0, r2+1, c2);
- X }
- X}
- X
- X/* Set cursor position.
- X This sets the STDWIN text caret and calls wshow for the character
- X at the cursor.
- X The cursor position is clipped to the screen dimensions,
- X but it may sit on the right edge just beyond the last character. */
- X
- Xvoid
- Xvtsetcursor(vt, row, col)
- X VT *vt;
- X int row, col;
- X{
- X CLIPMAX(row, vt->rows - 1);
- X CLIPMIN(row, 0);
- X CLIPMAX(col, vt->cols);
- X CLIPMIN(col, 0);
- X vt->cur_row = row;
- X vt->cur_col = col;
- X CLIPMAX(col, vt->cols - 1);
- X if (!vt->lazy) {
- X VTENDDRAWING(vt);
- X wsetcaret(vt->win, col * vt->cwidth, row * vt->cheight);
- X vtshow(vt, row, col, row + 1, col);
- X }
- X}
- X
- X/* Set scrolling region. Lines in [top...bot) can scroll.
- X If the parameters are valid, set the region and move to (0, 0);
- X if there is an error, reset the region and don't move.
- X (NB: the move is to (0, 0), not to the top of the region!) */
- X
- Xvoid
- Xvtsetscroll(vt, top, bot)
- X VT *vt;
- X int top, bot;
- X{
- X vtsync(vt);
- X if (top >= vt->topterm && top < bot && bot <= vt->rows) {
- X vt->scr_top = top;
- X vt->scr_bot = bot;
- X vtsetcursor(vt, vt->topterm, 0);
- X /* vtshow(vt, vt->topterm, 0, vt->rows, vt->cols); */
- X }
- X else {
- X vt->scr_top = vt->topterm;
- X vt->scr_bot = vt->rows;
- X }
- X vtshow(vt, vt->scr_top, 0, vt->scr_bot, vt->cols);
- X}
- X
- X/* Major reset */
- X
- Xvoid
- Xvtreset(vt)
- X VT *vt;
- X{
- X int row;
- X
- X vtchange(vt, 0, 0, vt->rows, vt->cols);
- X vtshow(vt, vt->topterm, 0, vt->rows, vt->cols);
- X
- X for (row = 0; row < vt->rows; ++row)
- X vt->llen[row] = 0;
- X
- X vt->toscroll = 0;
- X vtsetflags(vt, 0);
- X vtsetinsert(vt, FALSE);
- X vtsetscroll(vt, 0, 0);
- X vtsetcursor(vt, vt->topterm, 0);
- X vt->sel_col1 = vt->sel_row1 = 0;
- X vt->sel_col2 = vt->sel_row2 = 0;
- X vt->save_row = vt->save_col = 0;
- X vt->keypadmode = FALSE;
- X vt->lazy = FALSE;
- X vt->mitmouse = FALSE;
- X vt->visualbell = FALSE;
- X vt->flagschanged = TRUE;
- X vt->action = NULL; /* This invalidates all other parsing fields */
- X}
- X
- X/* Draw procedure - this one is called because stdwin discovered an expose */
- X
- XSTATIC void
- Xvtdrawproc(win, left, top, right, bottom)
- X WINDOW *win;
- X int left, top, right, bottom;
- X{
- X VT *vt = vtfind(win);
- X
- X#ifndef NDEBUG
- X if (vt == NULL) vtpanic("vtdrawproc not for VT window");
- X if (vt->drawing) vtpanic("vtdrawproc while drawing");
- X#endif
- X
- X vt->drawing = 1; /* Stdwin did this implicitely */
- X {
- X int cw = vt->cwidth;
- X int ch = vt->cheight;
- X int col1 = left / cw;
- X int col2 = (right + cw - 1) / cw;
- X int row1 = top / ch;
- X int row2 = (bottom + ch - 1) / vt->cheight;
- X
- X D( printf("vtdrawproc: ") );
- X vtdraw(vt, row1, col1, row2, col2);
- X }
- X vt->drawing = 0; /* Stdwin will do this implicitely */
- X}
- X
- XSTATIC void
- Xset_textstyle(vt, flags)
- X VT *vt;
- X int flags;
- X{
- X#if 0
- X /* This isn't right, for various reasons. And do we need it? */
- X static int previous_flags = -3; /* Or anything < 0 */
- X
- X if (flags == previous_flags) return;
- X D( printf("Set_textstyle: 0x%x => 0x%x\n", previous_flags, flags) );
- X previous_flags = flags;
- X#endif
- X wsetplain();
- X if (flags & VT_UNDERLINE) wsetunderline();
- X if (flags & VT_INVERSE) wsetinverse();
- X#ifdef DO_BOLD
- X if (flags & VT_BOLD) SETBOLD();
- X else SETNORMAL();
- X#endif
- X}
- X
- X/* Draw procedure - doesn't draw [row2, col2], or any other
- X char at row2, takes care of underlining, inverse video etc */
- X
- XSTATIC void
- Xvtdraw(vt, row1, col1, row2, col2)
- X VT *vt;
- X int row1, col1, row2, col2;
- X{
- X int cw = vt->cwidth;
- X int ch = vt->cheight;
- X register unsigned char cur_flags;
- X int row;
- X
- X VTBEGINDRAWING(vt);
- X D( printf("vtdraw [%d,%d]~[%d,%d]\n", col1, row1, col2, row2) );
- X
- X CLIPMIN(col1, 0);
- X CLIPMAX(col2, vt->cols);
- X CLIPMIN(row1, 0);
- X CLIPMAX(row2, vt->rows);
- X
- X for (row = row1; row < row2; ++row) {
- X register int col;
- X char *data_row = vt->data[row] + col1;
- X register unsigned char *flags_row = vt->flags[row] + col1;
- X int h = col1*cw;
- X int v = row*ch;
- X int first = col1;
- X register int last = vt->llen[row];
- X
- X CLIPMAX(last, col2); /* Don't draw more than asked for */
- X
- X /* Set flags */
- X cur_flags = flags_row[0];
- X set_textstyle(vt, cur_flags);
- X
- X /* Attempt to draw as much text as possible in one wdrawtext */
- X for (col = first; col < last; ++col) {
- X if (*flags_row++ != cur_flags) {
- X int n = col-first;
- X /* n cannot be < 0; ==0 means this
- X line has different flags */
- X if (n > 0) {
- X wdrawtext(h, v, data_row, n);
- X first = col;
- X data_row += n;
- X h += n*cw;
- X }
- X
- X cur_flags = flags_row[-1]; /* Set new flags */
- X set_textstyle(vt, cur_flags);
- X }
- X }
- X /* Draw leftover text on this line and perhaps some black spaces: */
- X if (col > first) wdrawtext(h, v, data_row, col-first);
- X }
- X}
- X
- X/* Find the VT corresponding to a WINDOW */
- X
- XVT *
- Xvtfind(win)
- X WINDOW *win;
- X{
- X int i;
- X for (i = 0; i < nvt; ++i) {
- X if (vtlist[i]->win == win)
- X return vtlist[i];
- X }
- X return NULL;
- X}
- X
- X/* Subroutine to circulate lines.
- X For i in r1 ... r2-1, move line i to position i+n (modulo r2-r1).
- X
- X For ABS(n)==1, we have a fast solution that always works.
- X For larger n, we have a slower solution allocating a temporary buffer;
- X if we can't, we repeat the fast solution ABS(n) times (really slow).
- X
- X We assume reasonable input:
- X 0 <= r1 < r2 <= vt->rows,
- X 0 < abs(n) < r2-r1.
- X*/
- X
- Xvoid
- Xvtcirculate(vt, r1, r2, n)
- X register VT *vt;
- X int r1, r2;
- X int n;
- X{
- X if (n == -1) { /* Fast solution, move 1 up */
- X char *tdata = vt->data[r1];
- X unsigned char *tflags = vt->flags[r1];
- X short tllen = vt->llen[r1];
- X register int i;
- X MON_EVENT("circulate -1");
- X for (i = r1+1; i < r2; ++i) {
- X vt->data[i-1] = vt->data[i];
- X vt->flags[i-1] = vt->flags[i];
- X vt->llen[i-1] = vt->llen[i];
- X }
- X vt->data[i-1] = tdata;
- X vt->flags[i-1] = tflags;
- X vt->llen[i-1] = tllen;
- X }
- X else if (n == 1) { /* Fast solution, move 1 down */
- X char *tdata = vt->data[r2-1];
- X unsigned char *tflags = vt->flags[r2-1];
- X short tllen = vt->llen[r2-1];
- X register int i;
- X MON_EVENT("circulate 1");
- X for (i = r2-1; i > r1; --i) {
- X vt->data[i] = vt->data[i-1];
- X vt->flags[i] = vt->flags[i-1];
- X vt->llen[i] = vt->llen[i-1];
- X }
- X vt->data[i] = tdata;
- X vt->flags[i] = tflags;
- X vt->llen[i] = tllen;
- X }
- X else if (n != 0) {
- X if (!slowcirculate(vt, r1, r2, n)) {
- X /* Couldn't -- do ABS(n) times the fast case... */
- X int step;
- X if (n < 0) {
- X n = -n;
- X step = -1;
- X }
- X else step = 1;
- X while (--n >= 0)
- X vtcirculate(vt, r1, r2, step);
- X }
- X }
- X}
- X
- X/* Slow version of the above; move lines r1..r2-1 n lines up */
- X
- XSTATIC bool
- Xslowcirculate(vt, r1, r2, n)
- X register VT *vt;
- X int r1, r2;
- X int n; /* May be negative */
- X{
- X char **tdata; /* Data buffer */
- X unsigned char **tflags; /* Flags buffer */
- X short *tllen; /* Line length buffer */
- X bool ok;
- X
- X if (n < 0) n += (r2 - r1);
- X tdata = NALLOC(char *, n);
- X tflags = NALLOC(unsigned char *, n);
- X tllen = NALLOC(short, n);
- X
- X MON_EVENT("slowcirculate");
- X /* Did all the malloc's work? */
- X ok = tdata != NULL && tflags != NULL && tllen != NULL;
- X if (ok) {
- X register int i;
- X r2 -= n; /* Now r2 "points" beyond the last target line */
- X /* Save data, flags and lengths to be overwritten */
- X for (i = 0; i < n; ++i) {
- X tdata[i] = vt->data[r2+i];
- X tflags[i] = vt->flags[r2+i];
- X tllen[i] = vt->llen[r2+i];
- X }
- X /* Copy "lower" part of the lines to r1..r1+n-1 (=r2-1) */
- X for (i = r2; --i >= r1; ) {
- X vt->data[i+n] = vt->data[i];
- X vt->flags[i+n] = vt->flags[i];
- X vt->llen[i+n] = vt->llen[i];
- X }
- X /* Restore saved lines in r1..r1+n-1 */
- X for (i = 0; i < n; ++i) {
- X vt->data[r1+i] = tdata[i];
- X vt->flags[r1+i] = tflags[i];
- X vt->llen[r1+i] = tllen[i];
- X }
- X }
- X
- X FREE(tdata);
- X FREE(tflags);
- X FREE(tllen);
- X
- X return ok;
- X}
- X
- X/* VT interface to wchange */
- X
- Xvoid
- Xvtchange(vt, r1, c1, r2, c2)
- X VT *vt;
- X int r1, c1, r2, c2;
- X{
- X VTENDDRAWING(vt);
- X D( printf("vtchange [%d, %d]~[%d, %d]\n", c1, r1, c2, r2) );
- X wchange(vt->win,
- X c1 * vt->cwidth, r1 * vt->cheight,
- X c2 * vt->cwidth, r2 * vt->cheight);
- X}
- X
- X/* VT interface to wshow */
- X
- Xvoid
- Xvtshow(vt, r1, c1, r2, c2)
- X VT *vt;
- X int r1, c1, r2, c2;
- X{
- X VTENDDRAWING(vt);
- X wshow(vt->win,
- X c1 * vt->cwidth, r1 * vt->cheight,
- X c2 * vt->cwidth, r2 * vt->cheight);
- X}
- X
- X/* VT interface to wscroll.
- X In lazy mode, the actual scrolling may be postponed
- X (by setting vt->toscroll). */
- X
- Xvoid
- Xvtscroll(vt, r1, c1, r2, c2, drow, dcol)
- X VT *vt;
- X int r1, c1, r2, c2;
- X int drow, dcol; /* Translation vector */
- X{
- X int scr_top = vt->scr_top;
- X if (scr_top == vt->topterm)
- X scr_top = 0;
- X
- X D( printf("vtscroll %d lines\n", drow) );
- X
- X if (vt->lazy && dcol == 0 && r1 == scr_top && r2 == vt->scr_bot &&
- X c1 == 0 && c2 == vt->cols) {
- X if (drow * vt->toscroll < 0)
- X vtsync(vt);
- X vt->toscroll += drow;
- X }
- X else {
- X if (vt->toscroll != 0 && r1 < vt->scr_bot && r2 > scr_top)
- X vtsync(vt); /* Execute leftover scrolling first */
- X
- X /* Convert to STDWIN coordinates */
- X c1 *= vt->cwidth;
- X c2 *= vt->cwidth;
- X dcol *= vt->cwidth;
- X
- X r1 *= vt->cheight;
- X r2 *= vt->cheight;
- X drow *= vt->cheight;
- X
- X VTENDDRAWING(vt);
- X wnocaret(vt->win);
- X wscroll(vt->win, c1, r1, c2, r2, dcol, drow);
- X
- X /* Despite what the stdwin document says,
- X wscroll doesn't generate wchanges anymore */
- X if (vt->lazy) {
- X if (drow < 0) { /* Scrolled upwards */
- X wchange(vt->win, c1, r2+drow, c2, r2);
- X D( printf("^: wchange(%d, %d, %d, %d)\n",
- X c1, r2+drow, c2, r2) );
- X }
- X else if (drow > 0) { /* Scrolled downwards */
- X wchange(vt->win, c1, r1, c2, r1+drow);
- X D( printf("V: wchange(%d, %d, %d, %d)\n",
- X c1, r1, c2, r1+drow) );
- X }
- X if (dcol < 0) { /* Scrolled to the left */
- X wchange(vt->win, c2+dcol, r1, c2, r2);
- X D( printf("<: wchange(%d, %d, %d, %d)\n",
- X c2+dcol, r1, c2, r2) );
- X }
- X else if (dcol > 0) { /* Scrolled to the right */
- X wchange(vt->win, c1, r1, c1+dcol, r2);
- X D( printf(">: wchange(%d, %d, %d, %d)\n",
- X c1, r1, c1+dcol, r2) );
- X }
- X }
- X }
- X}
- X
- X/* Execute delayed scrolling.
- X Don't call from within drawproc: wscroll while drawing is BAD. */
- X
- Xvoid
- Xvtsync(vt)
- X VT *vt;
- X{
- X VTENDDRAWING(vt);
- X if (vt->toscroll != 0) {
- X int scr_top = vt->scr_top;
- X#if 0
- X /* XXX Why not? */
- X if (vt->toscroll < 0) vtpanic("vtsync: toscroll < 0");
- X#endif
- X if (scr_top == vt->topterm)
- X scr_top = 0;
- X D( printf("VtSync [,%d]~[,%d] %d: wscroll\n",
- X scr_top, vt->scr_bot, vt->toscroll) );
- X wscroll(vt->win,
- X 0, scr_top * vt->cheight,
- X vt->cols * vt->cwidth, vt->scr_bot * vt->cheight,
- X 0, vt->toscroll * vt->cheight);
- X
- X D( printf("vtsync: ") );
- X /* I could get speedup from remembering
- X * min and max columns for the call here
- X */
- X vtchange(vt, vt->scr_bot + vt->toscroll, 0,
- X vt->scr_bot, vt->cols);
- X vt->toscroll = 0;
- X }
- X /* vtsetcursor doesn't do this if vt->lazy: */
- X if (vt->lazy) {
- X MON_EVENT("vtsync for lazy");
- X wsetcaret(vt->win,
- X vt->cur_col * vt->cwidth,
- X vt->cur_row * vt->cheight);
- X vtshow(vt, vt->cur_row,vt->cur_col, vt->cur_row+1,vt->cur_col);
- X }
- X}
- X
- X/* Internal VT interface to winvert.
- X Must be called between wbegindrawing and wenddrawing. */
- X
- Xvoid
- Xvtinvert(vt, row1, col1, row2, col2)
- X VT *vt;
- X int row1, col1, row2, col2;
- X{
- X /* XXX Here was some code */
- X
- X if (row1 == row2) {
- X /* Whole selection within one line */
- X winvert(col1 * vt->cwidth, row1 * vt->cheight,
- X col2 * vt->cwidth, (row2 + 1) * vt->cheight);
- X }
- X else {
- X /* Invert first line of the selection */
- X winvert(col1 * vt->cwidth, row1 * vt->cheight,
- X vt->cols * vt->cwidth, (row1 + 1) * vt->cheight);
- X
- X /* Invert intermediate lines, if any */
- X if (row1 + 1 < row2) {
- X winvert(0, (row1 + 1) * vt->cheight,
- X vt->cols * vt->cwidth, row2 * vt->cheight);
- X }
- X
- X /* Invert last line */
- X winvert(0, row2 * vt->cheight,
- X col2 * vt->cwidth, (row2 + 1) * vt->cheight);
- X }
- X}
- END_OF_FILE
- if test 20134 -ne `wc -c <'Packs/vt/vt.c'`; then
- echo shar: \"'Packs/vt/vt.c'\" unpacked with wrong size!
- fi
- # end of 'Packs/vt/vt.c'
- fi
- if test -f 'Ports/x11/window.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Ports/x11/window.c'\"
- else
- echo shar: Extracting \"'Ports/x11/window.c'\" \(30704 characters\)
- sed "s/^X//" >'Ports/x11/window.c' <<'END_OF_FILE'
- X/* X11 STDWIN -- Window operations */
- X
- X#include "x11.h"
- X#include "llevent.h"
- X#include <X11/Xutil.h> /* For Rectangle{In,Out,Part} */
- X
- X
- X/* Margin size around inner window (space for scroll and menu bars) */
- X
- X#define LMARGIN 16
- X/*
- X#define TMARGIN (MIN((_wmf->ascent + _wmf->descent), 16) + 2)
- X*/
- X#define TMARGIN 18
- X#define RMARGIN 0
- X#define BMARGIN 16
- X#define IMARGIN 2
- X
- X
- X/* Event masks */
- X
- X/* Mask for 'wo' */
- X#define OUTER_MASK ( KeyPressMask \
- X | FocusChangeMask \
- X | EnterWindowMask \
- X | LeaveWindowMask \
- X | StructureNotifyMask \
- X )
- X
- X/* Mask for other windows except 'wi' */
- X#define OTHER_MASK ( ButtonPressMask \
- X | ButtonReleaseMask \
- X | ButtonMotionMask \
- X | ExposureMask \
- X )
- X
- X
- X/* Private globals */
- X
- Xstatic int def_h, def_v;
- Xstatic int def_width, def_height;
- X
- X#define DEF_WIDTH (def_width > 0 ? def_width : 80*wcharwidth('n'))
- X#define DEF_HEIGHT (def_height > 0 ? def_height : 22*wlineheight())
- X
- X
- X/* WINDOW list.
- X Each WINDOW must be registered here, so it can be found back
- X by _whichwin */
- X
- Xstatic WINDOW **winlist;
- Xstatic int nwins;
- X
- X
- X/* Find a WINDOW pointer, given a Window.
- X Hunt through the WINDOW list, for each element comparing the given wid
- X with the wids of all (sub)Windows */
- X
- XWINDOW *
- X_whichwin(w)
- X register Window w;
- X{
- X register int i;
- X
- X for (i= nwins; --i >= 0; ) {
- X register WINDOW *win= winlist[i];
- X register int j;
- X for (j= NSUBS; --j >= 0; ) {
- X if (w == win->subw[j].wid)
- X return win;
- X }
- X }
- X _wdebug(2, "_whichwin: can't find Window %x", w);
- X return NULL;
- X}
- X
- X
- X/* Return some window */
- X
- XWINDOW *
- X_w_somewin()
- X{
- X if (nwins <= 0)
- X return NULL;
- X return winlist[0];
- X}
- X
- X
- X/* Set the max size of windows created later (ignored for now) */
- X
- Xvoid
- Xwsetmaxwinsize(width, height)
- X int width, height;
- X{
- X}
- X
- X
- X/* Set the initial size of windows created later */
- X
- Xvoid
- Xwsetdefwinsize(width, height)
- X int width, height;
- X{
- X if (width <= 0)
- X def_width= 0;
- X else {
- X CLIPMAX(width, WidthOfScreen(_ws) - 40 - LMARGIN - RMARGIN);
- X CLIPMIN(width, 40);
- X def_width= width;
- X }
- X if (height <= 0)
- X def_height= 0;
- X else {
- X CLIPMAX(height, HeightOfScreen(_ws) - 40 - TMARGIN - BMARGIN);
- X CLIPMIN(height, 40);
- X def_height= height;
- X }
- X}
- X
- Xvoid
- Xwgetdefwinsize(pwidth, pheight)
- X int *pwidth, *pheight;
- X{
- X *pheight = def_height;
- X *pwidth = def_width;
- X}
- X
- X
- X/* Set the initial position of windows created later */
- X
- Xvoid
- Xwsetdefwinpos(h, v)
- X int h, v;
- X{
- X CLIPMIN(h, 0);
- X CLIPMIN(v, 0);
- X def_h= h;
- X def_v= v;
- X}
- X
- Xvoid
- Xwgetdefwinpos(ph, pv)
- X int *ph, *pv;
- X{
- X *ph = def_h;
- X *pv = def_v;
- X}
- X
- X
- X/* Read a Bitmap from a file and convert it to a Pixmap.
- X XXX Actually I don't convert it to a Pixmap; this may mean that perhaps
- X you won't be able to set an icon on a color display, depending
- X on the intelligence of the window manager.
- X XXX Note that to fix this you must create separate functions to read
- X Bitmaps and Pixmaps, as Bitmaps have a real use (for icon masks). */
- X
- X#define readpixmap readbitmap
- X
- X/* Read a bitmap from file */
- X
- Xstatic Pixmap
- Xreadbitmap(filename)
- X char *filename;
- X{
- X unsigned int width, height;
- X int xhot, yhot;
- X Pixmap bitmap;
- X int err= XReadBitmapFile(_wd, RootWindowOfScreen(_ws), filename,
- X &width, &height, &bitmap, &xhot, &yhot);
- X if (err != BitmapSuccess) {
- X _wwarning("can't read bitmap file %s, error code %d",
- X filename, err);
- X return None;
- X }
- X return bitmap;
- X}
- X
- X
- X/* Open a WINDOW.
- X Some defaults should only be used for the first window opened,
- X e.g., window geometry (otherwise all windows would overlay each other!)
- X and the "iconic" property. Icon bitmaps will be used by all windows. */
- X
- XWINDOW *
- Xwopen(title, drawproc)
- X char *title;
- X void (*drawproc)();
- X{
- X static bool used_defaults;
- X WINDOW *win;
- X XSizeHints sizehints;
- X
- X /* Allocate zeroed storage for the WINDOW structure
- X and fill in the easy non-zero values */
- X win= (WINDOW*) calloc(sizeof(WINDOW), 1);
- X if (win == NULL) {
- X _werror("wopen: can't alloc storage for window");
- X return NULL;
- X }
- X win->drawproc= drawproc;
- X win->careth= win->caretv= -1;
- X win->attr= wattr;
- X
- X /* Parse user-specified geometry default.
- X This overrides what the application specified.
- X Note that the x and y stored internally are exclusive or borders,
- X while X geometries specify x and y including the border.
- X XXX Also note that the obsolete sizehints members x, y, width and
- X height are used later to actually create the window. */
- X {
- X char *geom;
- X sizehints.x= def_h <= 0 ? 0 : def_h - 2*IBORDER;
- X sizehints.y= def_v <= 0 ? 0 : def_v - 2*IBORDER;
- X sizehints.width= DEF_WIDTH + LMARGIN + RMARGIN;
- X sizehints.height= DEF_HEIGHT + TMARGIN + BMARGIN;
- X sizehints.flags= PSize;
- X if (def_h > 0 || def_v > 0)
- X sizehints.flags |= PPosition | USPosition;
- X /* USPosition added to fool twm */
- X if (!used_defaults &&
- X (geom= _wgetdefault("geometry", "Geometry")) != NULL){
- X unsigned int width, height;
- X int flags= XParseGeometry(geom,
- X &sizehints.x, &sizehints.y, &width, &height);
- X if (flags & WidthValue)
- X sizehints.width = width;
- X if (flags & HeightValue)
- X sizehints.height = height;
- X if (flags & XNegative)
- X sizehints.x=
- X WidthOfScreen(_ws) + sizehints.x
- X - sizehints.width - 2*IBORDER;
- X if (flags & YNegative)
- X sizehints.y=
- X HeightOfScreen(_ws) + sizehints.y
- X - sizehints.height - 2*IBORDER;
- X
- X /* Use the user-specified size as the default
- X size for future windows */
- X
- X if (flags & WidthValue)
- X def_width=
- X sizehints.width - LMARGIN - RMARGIN;
- X if (flags & HeightValue)
- X def_height=
- X sizehints.height - TMARGIN - BMARGIN;
- X
- X /* If the user has given as position,
- X pretend a size is also given, otherwise
- X UWM will still ask for interactive
- X window placement. I'm in good company:
- X "the" Toolkit also does this. */
- X
- X if (flags & (XValue|YValue))
- X sizehints.flags |= USPosition|USSize;
- X else if (flags & (WidthValue|HeightValue))
- X sizehints.flags |= USSize;
- X
- X#if 1
- X /* XXX This doesn't compile in R3.
- X It's safe to take it out. */
- X
- X /* Derive the gravity hint from the geometry */
- X
- X if ((flags & XNegative) || (flags & YNegative)) {
- X sizehints.flags |= PWinGravity;
- X if (flags & XNegative) {
- X if (flags & YNegative)
- X sizehints.win_gravity =
- X SouthEastGravity;
- X else
- X sizehints.win_gravity =
- X NorthEastGravity;
- X }
- X else
- X sizehints.win_gravity =
- X SouthWestGravity;
- X }
- X#endif
- X /* XXX Do we need a resource to specify the min
- X size (or base size), max size and size
- X increment? Better to let the application
- X decide based upon the font used? */
- X }
- X }
- X
- X /* Set the initial geometry from the size hints just computed */
- X win->wo.border= 2*IBORDER;
- X win->wo.x= sizehints.x + win->wo.border;
- X win->wo.y= sizehints.y + win->wo.border;
- X win->wo.width= sizehints.width;
- X win->wo.height= sizehints.height;
- X
- X /* Set the foreground and background pixel values */
- X win->fga= _wgetpixel("foreground", "Foreground",
- X BlackPixelOfScreen(_ws));
- X win->bga= _wgetpixel("background", "Background",
- X WhitePixelOfScreen(_ws));
- X win->fgo= _wgetpixel("menuForeground", "Foreground", win->fga);
- X win->bgo= _wgetpixel("menuBackground", "Background", win->bga);
- X
- X /* Swap the pixel values if 'reverse' specified */
- X if (_wgetbool("reverse", "Reverse", 0)) {
- X unsigned long temp= win->fga;
- X win->fga= win->bga;
- X win->bga= temp;
- X temp= win->fgo;
- X win->fgo= win->bgo;
- X win->bgo= temp;
- X }
- X
- X /* Create the outer Window */
- X if (!_wcreate(&win->wo, RootWindowOfScreen(_ws), 0, FALSE,
- X win->fgo, win->bgo)) {
- X FREE(win);
- X return NULL;
- X }
- X
- X /* Create the inner subWindows */
- X if (!_wmakesubwins(win)) {
- X FREE(win);
- X return NULL;
- X }
- X
- X /* Create the Graphics Contexts */
- X win->gc= _wgcreate(win->wo.wid, _wmf->fid, win->fgo, win->bgo);
- X win->gca= _wgcreate(win->wa.wid, _wf->fid, win->fga, win->bga);
- X
- X /* Change selected Window properties */
- X _wsetmasks(win);
- X _w_setgrayborder(win);
- X
- X /* Set the "invalid" region to empty (rely on Expose events) */
- X win->inval= XCreateRegion();
- X
- X /* Initialize the menu bar stuff */
- X _waddmenus(win);
- X
- X /* Set window properties */
- X
- X /* Set window and icon names */
- X {
- X char *windowname = title;
- X char *iconname = NULL;
- X char *p;
- X
- X /* Resources may override these for the first window */
- X if (!used_defaults) {
- X if ((p = _wgetdefault("title", "Title")) != NULL)
- X windowname = iconname = p;
- X if ((p = _wgetdefault("iconName", "IconName")) != NULL)
- X iconname = p;
- X }
- X
- X XStoreName(_wd, win->wo.wid, windowname);
- X /* Only store the icon name if specified -- the WM will
- X derive a default from the title otherwise. */
- X if (iconname != NULL)
- X XSetIconName(_wd, win->wo.wid, iconname);
- X }
- X
- X /* Set command line (computed by winitargs()) */
- X XChangeProperty(_wd, win->wo.wid,
- X XA_WM_COMMAND, XA_STRING, 8, PropModeReplace,
- X (unsigned char *)_wm_command, _wm_command_len);
- X /* XXX The ICCCM prescribes that exactly one window
- X of a given client has this property. Later. */
- X
- X /* Set normal size hints (computed above) */
- X XSetNormalHints(_wd, win->wo.wid, &sizehints);
- X
- X /* Set WM Hints */
- X {
- X XWMHints wmhints;
- X char *value;
- X wmhints.flags= InputHint | StateHint;
- X wmhints.input= _wgetbool("input", "Input", 1);
- X if (!used_defaults &&
- X _wgetbool("iconic", "Iconic", 0))
- X wmhints.initial_state= IconicState;
- X else
- X wmhints.initial_state= NormalState;
- X if (!used_defaults && (value=
- X _wgetdefault("iconGeometry", "IconGeometry"))
- X != NULL) {
- X unsigned int width, height;
- X int flags= XParseGeometry(value,
- X &wmhints.icon_x, &wmhints.icon_y,
- X &width, &height);
- X if (flags & XNegative)
- X wmhints.icon_x=
- X WidthOfScreen(_ws) - wmhints.icon_x;
- X if (flags & YNegative)
- X wmhints.icon_y=
- X HeightOfScreen(_ws) - wmhints.icon_y;
- X if (flags & (XValue|YValue)) {
- X wmhints.flags |= IconPositionHint;
- X _wdebug(1, "icon pos: %d,%d",
- X wmhints.icon_x, wmhints.icon_y);
- X }
- X else
- X _wdebug(1, "no icon pos");
- X }
- X value= _wgetdefault("iconBitmap", "IconBitmap");
- X if (value != NULL) {
- X wmhints.icon_pixmap= readpixmap(value);
- X if (wmhints.icon_pixmap != None)
- X wmhints.flags |= IconPixmapHint;
- X }
- X value= _wgetdefault("iconMask", "IconMask");
- X if (value != NULL) {
- X wmhints.icon_mask= readbitmap(value);
- X if (wmhints.icon_mask != None)
- X wmhints.flags |= IconMaskHint;
- X }
- X /* XXX What about window groups? */
- X XSetWMHints(_wd, win->wo.wid, &wmhints);
- X }
- X
- X /* Set class (same as strings used by _wgetdefault() */
- X {
- X XClassHint classhint;
- X classhint.res_name= _wprogname;
- X classhint.res_class= "Stdwin";
- X XSetClassHint(_wd, win->wo.wid, &classhint);
- X }
- X
- X /* Set client machine */
- X XChangeProperty(_wd, win->wo.wid,
- X XA_WM_CLIENT_MACHINE, XA_STRING, 8, PropModeReplace,
- X (unsigned char *)_whostname, strlen(_whostname));
- X
- X /* Set protocols property */
- X {
- X static Atom protocols[] = {
- X 0 /*XA_WM_DELETE_WINDOW*/,
- X };
- X protocols[0] = _wm_delete_window;
- X XChangeProperty(_wd, win->wo.wid,
- X _wm_protocols, XA_ATOM, 32, PropModeReplace,
- X (unsigned char *)protocols,
- X sizeof(protocols) / sizeof(protocols[0]));
- X }
- X
- X /* Store the WINDOW pointer in the list of windows */
- X L_APPEND(nwins, winlist, WINDOW *, win);
- X
- X /* Now we're ready, finally show the window, on top of others */
- X XMapRaised(_wd, win->wo.wid);
- X
- X /* Note that we've used the once-only defaults */
- X used_defaults= TRUE;
- X
- X /* Don't forget to return the WINDOW pointer */
- X return win;
- X}
- X
- X
- X/* Make a window the active window -- ICCCM version.
- X - De-iconify.
- X - Raise the window.
- X Any events that may follow from this are handled later when we get them.
- X*/
- X
- Xvoid
- Xwsetactive(win)
- X WINDOW *win;
- X{
- X XMapRaised(_wd, win->wo.wid); /* The ICCCM way to de-iconify */
- X XRaiseWindow(_wd, win->wo.wid);
- X}
- X
- X
- X/* Get a pixel value from the resource database */
- X
- Xunsigned long
- X_wgetpixel(resname, resclassname, defpixel)
- X char *resname;
- X char *resclassname;
- X unsigned long defpixel;
- X{
- X char *cname;
- X Colormap cmap;
- X XColor hard, exact;
- X
- X cname= _wgetdefault(resname, resclassname);
- X if (cname == NULL)
- X return defpixel;
- X cmap= DefaultColormapOfScreen(_ws);
- X if (!XParseColor(_wd, cmap, cname, &exact)) {
- X _wwarning("%s: no such color", cname);
- X return defpixel;
- X }
- X hard= exact;
- X if (!XAllocColor(_wd, cmap, &hard)) {
- X _wwarning("%s: can't allocate color cell", cname);
- X return defpixel;
- X }
- X return hard.pixel;
- X}
- X
- X
- X/* Return a gray pixmap */
- X
- XPixmap
- X_w_gray() {
- X#include <X11/bitmaps/gray>
- X/* defines gray_bits, gray_width, gray_height */
- X
- X static Pixmap gray;
- X
- X if (gray == 0) {
- X gray= XCreatePixmapFromBitmapData(_wd,
- X RootWindowOfScreen(_ws),
- X gray_bits, gray_width, gray_height,
- X BlackPixelOfScreen(_ws),
- X WhitePixelOfScreen(_ws),
- X DefaultDepthOfScreen(_ws));
- X }
- X
- X return gray;
- X}
- X
- X
- X/* Set the border pixmap of a window to a gray pattern */
- X
- Xvoid
- X_w_setgrayborder(win)
- X WINDOW *win;
- X{
- X XSetWindowBorderPixmap(_wd, win->wo.wid, _w_gray());
- X}
- X
- X
- X/* Create a Graphics Context using the given Window and Font ids.
- X Don't set the font if Font id is zero.
- X The plane mask is set to the XOR of the fg and bg colors;
- X if the window bg color is the same as the GC bg color,
- X this makes painting, erasing and XOR'ing possible
- X on color displays. (On monochrome displays, one of the colors
- X is 1, one is 0, so the XOR is 1, which means all the planes we have.
- X*/
- X
- XGC
- X_wgcreate(wid, fid, fg, bg)
- X Window wid;
- X Font fid;
- X unsigned long fg, bg;
- X{
- X int mask= GCForeground|GCBackground|GCPlaneMask;
- X XGCValues v;
- X
- X v.plane_mask= fg ^ bg;
- X v.foreground= fg;
- X v.background= bg;
- X if (fid != 0) {
- X v.font= fid;
- X mask |= GCFont;
- X }
- X return XCreateGC(_wd, wid, mask, &v);
- X}
- X
- X
- X/* Create a Window for a given windata struct and set its event mask.
- X If map is TRUE, also map it.
- X Initially, a window is not dirty (it'll get Expose events for that) */
- X
- Xbool
- X_wcreate1(wp, parent, cursor, map, fg, bg, nowm)
- X struct windata *wp;
- X Window parent;
- X int cursor;
- X bool map;
- X unsigned long fg, bg;
- X bool nowm;
- X{
- X XSetWindowAttributes attributes;
- X unsigned long valuemask=
- X CWBackPixel|CWBorderPixel|CWBitGravity|CWBackingStore;
- X
- X attributes.background_pixel= bg;
- X attributes.border_pixel= fg;
- X attributes.bit_gravity= NorthWestGravity;
- X if (nowm) {
- X attributes.override_redirect = 1;
- X valuemask |= CWOverrideRedirect;
- X }
- X/*
- X attributes.backing_store= WhenMapped;
- X*/
- X attributes.backing_store= NotUseful; /* Seems to be Harmful... */
- X
- X if (cursor > 0) {
- X attributes.cursor= XCreateFontCursor(_wd, cursor);
- X valuemask |= CWCursor;
- X }
- X
- X /* We must subtract border width from x and y before
- X passing them to WCreateSimpleWindow, since
- X they refer to the upper left corner of the border! */
- X
- X wp->wid= XCreateWindow(
- X _wd,
- X parent,
- X wp->x - wp->border, /* x */
- X wp->y - wp->border, /* y */
- X wp->width,
- X wp->height,
- X wp->border, /* border width */
- X CopyFromParent, /* depth */
- X InputOutput, /* class */
- X CopyFromParent, /* visual */
- X valuemask,
- X &attributes
- X );
- X if (!wp->wid) {
- X _werror("_wcreate: can't create (sub)Window");
- X return FALSE;
- X }
- X _wdebug(2, "_wcreate: wid=0x%x", wp->wid);
- X if (map)
- X XMapWindow(_wd, wp->wid);
- X wp->dirty= FALSE;
- X return TRUE;
- X}
- X
- X
- X/* Set the save-under property for a window given by a windata struct */
- X
- Xvoid
- X_wsaveunder(wp, flag)
- X struct windata *wp;
- X Bool flag;
- X{
- X static int saveUnder = -1;
- X XSetWindowAttributes attrs;
- X
- X /* The user may explicitly turn off save-unders by specifying
- X Stdwin*SaveUnder: off
- X since they are broken on some servers */
- X
- X if (saveUnder < 0) {
- X /* First time here: check resource database */
- X saveUnder = _wgetbool("saveUnder", "SaveUnder", 1);
- X if (!saveUnder)
- X _wdebug(1, "user doesn't want save-unders");
- X }
- X
- X if (!saveUnder)
- X return;
- X
- X attrs.save_under= flag;
- X XChangeWindowAttributes(_wd, wp->wid, CWSaveUnder, &attrs);
- X}
- X
- X
- X/* Set gravity for a window given by a windata struct */
- X
- Xstatic void
- X_wgravity(wp, grav)
- X struct windata *wp;
- X int grav;
- X{
- X XSetWindowAttributes attrs;
- X attrs.win_gravity= grav;
- X XChangeWindowAttributes(_wd, wp->wid, CWWinGravity, &attrs);
- X}
- X
- X
- X/* Move and resize a window given by a windata struct */
- X
- Xvoid
- X_wmove(wp)
- X struct windata *wp;
- X{
- X XMoveResizeWindow(_wd, wp->wid,
- X wp->x - wp->border, wp->y - wp->border, wp->width, wp->height);
- X}
- X
- X
- X/* (Re)compute the sizes and positions of all subwindows.
- X If aflag is set, the application subwindow is resized as well.
- X Note a check (in SZ) to prevent windows ever to get a size <= 0 */
- X
- Xstatic
- X_wsizesubwins(win)
- X WINDOW *win;
- X{
- X int bmargin= win->wi.height - win->doc.height - win->wa.y;
- X int rmargin= win->wi.width - win->doc.width - win->wa.x;
- X
- X#define SZ(elem, nx, ny, nw, nh, nb) \
- X (win->elem.x= (nx), \
- X win->elem.y= (ny), \
- X win->elem.width= (nw) > 0 ? (nw) : 1, \
- X win->elem.height= (nh) > 0 ? (nh) : 1, \
- X win->elem.border= (nb))
- X
- X /* Interior window in the middle */
- X SZ(wi, LMARGIN, TMARGIN,
- X win->wo.width - LMARGIN - RMARGIN,
- X win->wo.height - TMARGIN - BMARGIN, 0);
- X /* Menu bar at the top */
- X SZ(mbar, 0, 0, win->wo.width, TMARGIN - IBORDER, IBORDER);
- X /* Vbar left */
- X SZ(vbar, 0, win->wi.y, LMARGIN - IBORDER, win->wi.height, IBORDER);
- X /* Hbar at bottom (top would be ugly because of mbar) */
- X SZ(hbar, win->wi.x, win->wo.height - BMARGIN + IBORDER,
- X win->wi.width, BMARGIN - IBORDER, IBORDER);
- X
- X#undef SZ
- X
- X /* The document window (wa) is sized differently.
- X If it fits in the window, it is made the same size
- X and aligned at (0,0) no questions asked.
- X Otherwise, it is moved so that the window never shows more
- X outside it than before (if at all possible). */
- X
- X if (win->doc.width <= win->wi.width) {
- X win->wa.x= IMARGIN;
- X win->wa.width= win->wi.width;
- X }
- X else {
- X CLIPMIN(rmargin, IMARGIN);
- X CLIPMIN(win->wa.x, win->wi.width - win->wa.width - rmargin);
- X CLIPMAX(win->wa.x, IMARGIN);
- X win->wa.width= win->doc.width;
- X CLIPMIN(win->wa.width, win->wi.width - win->wa.x);
- X }
- X if (win->doc.height <= win->wi.height) {
- X win->wa.y= 0;
- X win->wa.height= win->wi.height;
- X }
- X else {
- X CLIPMIN(bmargin, 0);
- X CLIPMIN(win->wa.y, win->wi.height - win->wa.height - bmargin);
- X CLIPMAX(win->wa.y, 0);
- X win->wa.height= win->doc.height;
- X CLIPMIN(win->wa.height, win->wi.height - win->wa.y);
- X }
- X}
- X
- X
- X/* Create the permanently visible subwindows.
- X Return TRUE if all creations succeeded.
- X The inner window is created after all bars, so it lies on top,
- X and will receive clicks in its border */
- X
- Xstatic bool
- X_wmakesubwins(win)
- X WINDOW *win;
- X{
- X Window w= win->wo.wid;
- X unsigned long fg= win->fgo, bg= win->bgo;
- X
- X _wsizesubwins(win);
- X if (!( _wcreate(&win->mbar, w, XC_arrow, TRUE, fg, bg) &&
- X _wcreate(&win->vbar, w, XC_sb_v_double_arrow, TRUE, fg, bg) &&
- X _wcreate(&win->hbar, w, XC_sb_h_double_arrow, TRUE, fg, bg) &&
- X _wcreate(&win->wi, w, 0, TRUE, fg, bg) &&
- X _wcreate(&win->wa, win->wi.wid, XC_crosshair, TRUE,
- X fg, win->bga)))
- X return FALSE;
- X _wgravity(&win->hbar, SouthWestGravity);
- X return TRUE;
- X}
- X
- X
- X/* Resize all subwindows and move them to their new positions.
- X The application and current menu windows (WA, MWIN) are not resized.
- X The application window may be moved, however, to prevent exposing
- X parts outside the document that weren't visible earlier. */
- X
- Xvoid
- X_wmovesubwins(win)
- X WINDOW *win;
- X{
- X int i;
- X _wsizesubwins(win);
- X
- X for (i= 1; i <= WA; ++i)
- X _wmove(&win->subw[i]);
- X
- X /* Invalidate scroll bars after a resize */
- X win->hbar.dirty= win->vbar.dirty= _w_dirty= TRUE;
- X}
- X
- X
- X/* Set normal event masks for all (sub)Windows of a WINDOW */
- X
- Xvoid
- X_wsetmasks(win)
- X WINDOW *win;
- X{
- X int i;
- X
- X XSelectInput(_wd, win->wo.wid, OUTER_MASK);
- X for (i= 1; i <= WA; ++i) {
- X if (win->subw[i].wid != 0)
- X XSelectInput(_wd, win->subw[i].wid,
- X (i == WI) ? NoEventMask : OTHER_MASK);
- X }
- X}
- X
- X
- X/* Generate any pending size event. */
- X
- Xbool
- X_w_doresizes(ep)
- X EVENT *ep;
- X{
- X int i;
- X
- X for (i= nwins; --i >= 0; ) {
- X WINDOW *win= winlist[i];
- X if (win->resized) {
- X win->resized= FALSE;
- X ep->type= WE_SIZE;
- X ep->window= win;
- X if (i == 0)
- X _w_resized= FALSE;
- X return TRUE;
- X }
- X }
- X _w_resized= FALSE;
- X return FALSE;
- X}
- X
- X
- X/* Perform any pending window updates.
- X If the application subwindow needs an update,
- X either call its draw procedure or generate a WE_DRAW event
- X in the given event record (and then stop).
- X Return TRUE if an event was generated */
- X
- Xbool
- X_w_doupdates(ep)
- X EVENT *ep;
- X{
- X int i;
- X
- X for (i= nwins; --i >= 0; ) {
- X if (update(winlist[i], ep)) {
- X if (i == 0)
- X _w_dirty= FALSE;
- X return TRUE;
- X }
- X }
- X _w_dirty= FALSE;
- X return FALSE;
- X}
- X
- Xvoid
- Xwupdate(win)
- X WINDOW *win;
- X{
- X (void) update(win, (EVENT *)NULL);
- X}
- X
- X/* Update any parts of a window that need updating.
- X If the application window needs redrawing and there is no drawproc
- X and the 'ep' argument is non-nil,
- X construct a DRAW event and return TRUE. */
- X
- Xstatic bool
- Xupdate(win, ep)
- X WINDOW *win;
- X EVENT *ep;
- X{
- X bool ret= FALSE;
- X
- X if (win->mbar.dirty)
- X _wdrawmbar(win);
- X if (win->hbar.dirty)
- X _wdrawhbar(win);
- X if (win->vbar.dirty)
- X _wdrawvbar(win);
- X win->mbar.dirty= win->hbar.dirty= win->vbar.dirty= FALSE;
- X /* wi and wo have nothing that can be drawn! */
- X
- X if (win->wa.dirty && (win->drawproc != NULL || ep != NULL)) {
- X XRectangle clip;
- X int left, top, right, bottom;
- X XClipBox(win->inval, &clip);
- X left= clip.x;
- X top= clip.y;
- X right= left + clip.width;
- X bottom= top + clip.height;
- X CLIPMIN(left, -win->wa.x);
- X CLIPMIN(top, -win->wa.y);
- X CLIPMAX(right, win->wi.width - win->wa.x);
- X CLIPMAX(bottom, win->wi.height - win->wa.y);
- X _wdebug(3, "clip: (%d,%d) to (%d,%d)",
- X left, top, right, bottom);
- X if (left < right && top < bottom) {
- X _whidecaret(win);
- X if (win->drawproc != NULL) {
- X /* A bug in X11R2 XSetRegion prevents this
- X from working: */
- X#ifndef R2
- X /* Version for R3 or later */
- X XSetRegion(_wd, win->gca, win->inval);
- X#else
- X /* Version for R2 */
- X XSetClipRectangles(_wd, win->gca,
- X 0, 0, &clip, 1, Unsorted);
- X#endif
- X wbegindrawing(win);
- X werase(left, top, right, bottom);
- X (*win->drawproc)(win,
- X left, top, right, bottom);
- X wenddrawing(win);
- X XSetClipMask(_wd, win->gca, (Pixmap)None);
- X }
- X else {
- X XClearArea(_wd, win->wa.wid,
- X clip.x, clip.y,
- X clip.width, clip.height, FALSE);
- X ep->type= WE_DRAW;
- X ep->window= win;
- X ep->u.area.left= left;
- X ep->u.area.top= top;
- X ep->u.area.right= right;
- X ep->u.area.bottom= bottom;
- X ret= TRUE;
- X }
- X _wshowcaret(win);
- X }
- X XDestroyRegion(win->inval);
- X win->inval= XCreateRegion();
- X win->wa.dirty= FALSE;
- X }
- X return ret;
- X}
- X
- X
- X/* Close a window */
- X
- Xvoid
- Xwclose(win)
- X WINDOW *win;
- X{
- X int i;
- X for (i= 0; i < nwins; ++i) {
- X if (winlist[i] == win)
- X break;
- X }
- X if (i >= nwins) {
- X _werror("wclose: unknown window");
- X return;
- X }
- X L_REMOVE(nwins, winlist, WINDOW *, i);
- X _w_deactivate(win);
- X _w_delmenus(win);
- X XFreeGC(_wd, win->gc);
- X XFreeGC(_wd, win->gca);
- X XDestroyWindow(_wd, win->wo.wid);
- X XFlush(_wd); /* Make the effect immediate */
- X FREE(win);
- X}
- X
- X
- X/* Change a window's title */
- X
- Xvoid
- Xwsettitle(win, title)
- X WINDOW *win;
- X char *title;
- X{
- X XStoreName(_wd, win->wo.wid, title);
- X /* The icon name will not change */
- X}
- X
- X
- X/* Return a window's current title -- straight from the window property */
- X
- Xchar *
- Xwgettitle(win)
- X WINDOW *win;
- X{
- X static char *title = NULL;
- X
- X if (title != NULL)
- X free(title); /* Free result of previous call */
- X title = NULL; /* Just in case */
- X if (!XFetchName(_wd, win->wo.wid, &title))
- X _wwarning("wgettitle: no title set");
- X return title;
- X}
- X
- X
- X/* Change a window's icon name */
- X
- Xvoid
- Xwseticontitle(win, title)
- X WINDOW *win;
- X char *title;
- X{
- X XSetIconName(_wd, win->wo.wid, title);
- X}
- X
- X
- X/* Return a window's current icon name -- straight from the window property */
- X
- Xchar *
- Xwgeticontitle(win)
- X WINDOW *win;
- X{
- X static char *title = NULL;
- X
- X if (title != NULL)
- X free(title); /* Free result of previous call */
- X title = NULL; /* Just in case */
- X if (!XGetIconName(_wd, win->wo.wid, &title))
- X _wdebug(1, "wgeticontitle: no icon name set");
- X /* This may occur normally so don't make it a warning */
- X return title;
- X}
- X
- X
- X/* Get a window's size.
- X This is really the size of the visible part of the document. */
- X
- Xvoid
- Xwgetwinsize(win, pwidth, pheight)
- X WINDOW *win;
- X int *pwidth, *pheight;
- X{
- X *pwidth= win->wi.width - IMARGIN;
- X *pheight= win->wi.height;
- X}
- X
- X
- X/* Get a window's position relative to the root */
- X
- Xvoid
- Xwgetwinpos(win, ph, pv)
- X WINDOW *win;
- X int *ph, *pv;
- X{
- X Window child;
- X
- X if (!XTranslateCoordinates( _wd,
- X win->wo.wid,
- X RootWindowOfScreen(_ws),
- X 0, 0,
- X ph, pv,
- X &child)) {
- X
- X _wwarning("wgetwinpos: XTranslateCoordinates failed");
- X *ph = 0;
- X *pv = 0;
- X }
- X}
- X
- X
- X/* "Change" part of a document, i.e., post a WE_DRAW event */
- X
- Xvoid
- Xwchange(win, left, top, right, bottom)
- X WINDOW *win;
- X int left, top, right, bottom;
- X{
- X _wdebug(3, "wchange: %d %d %d %d", left, top, right, bottom);
- X if (left < right && top < bottom) {
- X XRectangle r;
- X r.x= left;
- X r.y= top;
- X r.width= right - left;
- X r.height= bottom - top;
- X XUnionRectWithRegion(&r, win->inval, win->inval);
- X win->wa.dirty= TRUE;
- X _w_dirty= TRUE;
- X }
- X}
- X
- X
- X/* "Scroll" part of a document, i.e., copy bits and erase the place
- X where they came from. May cause WE_DRAW events if source bits are
- X covered. */
- X
- Xvoid
- Xwscroll(win, left, top, right, bottom, dh, dv)
- X WINDOW *win;
- X int left, top, right, bottom;
- X int dh, dv;
- X{
- X int src_x= left, src_y= top;
- X int dest_x= left, dest_y= top;
- X int width= right - left - ABS(dh);
- X int height= bottom - top - ABS(dv);
- X
- X if (dh == 0 && dv == 0)
- X return;
- X
- X if (dh < 0)
- X src_x += -dh;
- X else
- X dest_x += dh;
- X if (dv < 0)
- X src_y += -dv;
- X else
- X dest_y += dv;
- X
- X _wdebug(2, "wscroll: src(%d,%d)size(%d,%d)dest(%d,%d)",
- X src_x, src_y, width, height, dest_x, dest_y);
- X _whidecaret(win);
- X XCopyArea(_wd, win->wa.wid, win->wa.wid, win->gca,
- X src_x, src_y, width, height, dest_x, dest_y);
- X _wshowcaret(win);
- X
- X if (XRectInRegion(win->inval, left, top, right-left, bottom-top)
- X != RectangleOut) {
- X /* Scroll the overlap between win->inval and the
- X scrolled rectangle:
- X scroll := <the entire scrolling rectangle>
- X overlap := inval * scroll
- X inval -:= overlap
- X shift overlap by (dh, dv)
- X overlap := overlap * scroll
- X inval +:= overlap
- X */
- X Region scroll = XCreateRegion();
- X Region overlap = XCreateRegion();
- X XRectangle r;
- X r.x = left;
- X r.y = top;
- X r.width = right-left;
- X r.height = bottom-top;
- X XUnionRectWithRegion(&r, scroll, scroll);
- X XIntersectRegion(win->inval, scroll, overlap);
- X XSubtractRegion(win->inval, overlap, win->inval);
- X XOffsetRegion(overlap, dh, dv);
- X XIntersectRegion(overlap, scroll, overlap);
- X XUnionRegion(win->inval, overlap, win->inval);
- X XDestroyRegion(overlap);
- X XDestroyRegion(scroll);
- X
- X /* There's still a bug left: exposure events in the queue
- X (like GraphicsExposures caused be previous scrolls!)
- X should be offset as well, bu this is too complicated
- X to fix right now... */
- X }
- X
- X /* Clear the bits scrolled in */
- X
- X if (dh > 0)
- X XClearArea(_wd, win->wa.wid,
- X left, top, dh, bottom-top, FALSE);
- X else if (dh < 0)
- X XClearArea(_wd, win->wa.wid,
- X right+dh, top, -dh, bottom-top, FALSE);
- X if (dv > 0)
- X XClearArea(_wd, win->wa.wid,
- X left, top, right-left, dv, FALSE);
- X else if (dv < 0)
- X XClearArea(_wd, win->wa.wid,
- X left, bottom+dv, right-left, -dv, FALSE);
- X}
- X
- X
- X/* Change the "origin" of a window (position of document, really) */
- X
- Xvoid
- Xwsetorigin(win, orgh, orgv)
- X WINDOW *win;
- X int orgh, orgv;
- X{
- X bool moveit= FALSE;
- X
- X CLIPMIN(orgh, 0);
- X CLIPMIN(orgv, 0);
- X if (win->wa.x != -orgh) {
- X win->hbar.dirty= moveit= TRUE;
- X win->wa.x= -orgh;
- X }
- X if (win->wa.y != -orgv) {
- X win->vbar.dirty= moveit= TRUE;
- X win->wa.y= -orgv;
- X }
- X if (moveit)
- X XMoveWindow(_wd, win->wa.wid, -orgh, -orgv);
- X}
- X
- X
- X/* Get the "origin" (see above) of a window */
- X
- Xvoid
- Xwgetorigin(win, ph, pv)
- X WINDOW *win;
- X int *ph, *pv;
- X{
- X *ph= -win->wa.x;
- X CLIPMIN(*ph, 0);
- X *pv= -win->wa.y;
- X}
- X
- X
- X/* Set the document size. Zero means don't use a scroll bar */
- X
- Xvoid
- Xwsetdocsize(win, width, height)
- X WINDOW *win;
- X int width, height;
- X{
- X bool dirty= FALSE;
- X
- X CLIPMIN(width, 0);
- X CLIPMIN(height, 0);
- X if (win->doc.width != width) {
- X win->doc.width= width;
- X if (width <= win->wo.width - IMARGIN) {
- X win->wa.x= IMARGIN;
- X win->wa.width= win->wi.width;
- X }
- X else {
- X win->wa.width= width;
- X CLIPMIN(win->wa.width, win->wi.width - win->wa.x);
- X }
- X win->hbar.dirty= dirty= TRUE;
- X }
- X if (win->doc.height != height) {
- X win->doc.height= height;
- X if (height <= win->wo.height) {
- X win->wa.y= 0;
- X win->wa.height= win->wi.height;
- X }
- X else {
- X win->wa.height= height;
- X }
- X win->vbar.dirty= dirty= TRUE;
- X }
- X if (dirty) {
- X _w_dirty= TRUE;
- X _wmove(&win->wa);
- X }
- X}
- X
- X
- X/* Return the document size last set by wsetdocsize() */
- X
- Xvoid
- Xwgetdocsize(win, pwidth, pheight)
- X WINDOW *win;
- X int *pwidth, *pheight;
- X{
- X *pwidth = win->doc.width;
- X *pheight = win->doc.height;
- X}
- X
- X
- X/* Change the cursor for a window */
- X
- Xvoid
- Xwsetwincursor(win, cursor)
- X WINDOW *win;
- X CURSOR *cursor;
- X{
- X Cursor c;
- X if (cursor == NULL)
- X c = None;
- X else
- X c = (Cursor) cursor;
- X XDefineCursor(_wd, win->wa.wid, c);
- X}
- X
- X
- X/* Scroll the document in the window to ensure that the given rectangle
- X is visible, if at all possible. Don't scroll more than necessary. */
- X
- Xvoid
- Xwshow(win, left, top, right, bottom)
- X WINDOW *win;
- X int left, top, right, bottom;
- X{
- X int orgh= -win->wa.x;
- X int orgv= -win->wa.y;
- X int winwidth, winheight;
- X int extrah, extrav;
- X
- X _wdebug(3, "wshow: %d %d %d %d", left, top, right, bottom);
- X
- X wgetwinsize(win, &winwidth, &winheight);
- X
- X if (left >= orgh &&
- X top >= orgv &&
- X right <= orgh + winwidth &&
- X bottom <= orgv + winheight)
- X return; /* Already visible */
- X
- X extrah= (winwidth - (right - left)) / 2;
- X CLIPMAX(extrah, win->doc.width - right);
- X CLIPMIN(extrah, 0);
- X orgh= right + extrah - winwidth;
- X CLIPMAX(orgh, left);
- X CLIPMIN(orgv, 0);
- X
- X extrav= (winheight - (bottom - top)) / 2;
- X CLIPMAX(extrav, win->doc.height - bottom);
- X CLIPMIN(extrav, 0);
- X orgv= bottom + extrav - winheight;
- X CLIPMAX(orgv, top);
- X CLIPMIN(orgv, 0);
- X
- X wsetorigin(win, orgh, orgv);
- X}
- X
- X
- X/* Sound the bell (beep) */
- X
- Xvoid
- Xwfleep()
- X{
- X XBell(_wd, 0);
- X}
- X
- X
- X/* Helper functions for the menu mananger: */
- X
- X_waddtoall(mp)
- X MENU *mp;
- X{
- X int i;
- X
- X for (i= nwins; --i >= 0; )
- X wmenuattach(winlist[i], mp);
- X}
- X
- X
- X_wdelfromall(mp)
- X MENU *mp;
- X{
- X int i;
- X
- X for (i= nwins; --i >= 0; )
- X wmenudetach(winlist[i], mp);
- X}
- X
- X
- X/* Helper function for the timer manager: */
- X
- XWINDOW *
- X_wnexttimer()
- X{
- X int i;
- X WINDOW *cand= NULL;
- X
- X for (i= nwins; --i >= 0; ) {
- X WINDOW *win= winlist[i];
- X long t= win->timer;
- X if (t != 0) {
- X if (cand == NULL || t < cand->timer)
- X cand= win;
- X }
- X }
- X return cand;
- X}
- X
- X
- X/* Delete all windows -- called by wdone() */
- X
- X_wkillwindows()
- X{
- X while (nwins > 0)
- X wclose(winlist[nwins-1]);
- X}
- END_OF_FILE
- if test 30704 -ne `wc -c <'Ports/x11/window.c'`; then
- echo shar: \"'Ports/x11/window.c'\" unpacked with wrong size!
- fi
- # end of 'Ports/x11/window.c'
- fi
- echo shar: End of archive 4 \(of 19\).
- cp /dev/null ark4isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 19 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-