guido@cwi.nl (Guido van Rossum) (03/04/91)
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