STDWIN 0.9.5, Part 04/19
Guido van Rossum
guido at cwi.nl
Mon Mar 4 21:57:42 AEST 1991
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 at 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
More information about the Alt.sources
mailing list