diff options
Diffstat (limited to 'src/runtime/rwindow.r')
-rw-r--r-- | src/runtime/rwindow.r | 1727 |
1 files changed, 1727 insertions, 0 deletions
diff --git a/src/runtime/rwindow.r b/src/runtime/rwindow.r new file mode 100644 index 0000000..752baa2 --- /dev/null +++ b/src/runtime/rwindow.r @@ -0,0 +1,1727 @@ +/* + * File: rwindow.r + * non window-system-specific window support routines + */ + +#ifdef Graphics + +static int setpos (wbp w, char *s); +static int sicmp (siptr sip1, siptr sip2); + +int canvas_serial, context_serial; + +#ifndef MultiThread +struct descrip amperX = {D_Integer}; +struct descrip amperY = {D_Integer}; +struct descrip amperCol = {D_Integer}; +struct descrip amperRow = {D_Integer}; +struct descrip amperInterval = {D_Integer}; +struct descrip lastEventWin = {D_Null}; +int lastEvFWidth = 0, lastEvLeading = 0, lastEvAscent = 0; +uword xmod_control, xmod_shift, xmod_meta; +#endif /* MultiThread */ + + +/* + * subscript the already-processed-events "queue" to index i. + * used in "cooked mode" I/O to determine, e.g. how far to backspace. + */ +char *evquesub(w,i) +wbp w; +int i; + { + wsp ws = w->window; + int j = ws->eQback+i; + + if (i < 0) { + if (j < 0) j+= EQUEUELEN; + else if (j > EQUEUELEN) j -= EQUEUELEN; + return &(ws->eventQueue[j]); + } + else { + /* "this isn't getting called in the forwards direction!\n" */ + return NULL; + } + } + + +/* + * get event from window, assigning to &x, &y, and &interval + * + * returns 0 for success, -1 if window died or EOF, -2 for malformed queue + */ +int wgetevent(w,res) +wbp w; +dptr res; + { + struct descrip xdesc, ydesc; + uword i; + + if (wstates != NULL && wstates->next != NULL /* if multiple windows*/ + && (BlkLoc(w->window->listp)->list.size == 0)) { /* & queue is empty */ + while (BlkLoc(w->window->listp)->list.size == 0) { + #ifdef WinGraphics + if (ISCURSORON(w) && w->window->hasCaret == 0) { + wsp ws = w->window; + CreateCaret(ws->iconwin, NULL, FWIDTH(w), FHEIGHT(w)); + SetCaretBlinkTime(500); + SetCaretPos(ws->x, ws->y - ASCENT(w)); + ShowCaret(ws->iconwin); + ws->hasCaret = 1; + } + #endif /* WinGraphics */ + if (pollevent() < 0) /* poll all windows */ + break; /* break on error */ + idelay(POLLSLEEP); + } + } + + if (wgetq(w,res) == -1) + return -1; /* window died */ + + if (BlkLoc(w->window->listp)->list.size < 2) + return -2; /* malformed queue */ + + wgetq(w,&xdesc); + wgetq(w,&ydesc); + + if (xdesc.dword != D_Integer || ydesc.dword != D_Integer) + return -2; /* bad values on queue */ + + IntVal(amperX) = IntVal(xdesc) & 0xFFFF; /* &x */ + if (IntVal(amperX) >= 0x8000) + IntVal(amperX) -= 0x10000; + IntVal(amperY) = IntVal(ydesc) & 0xFFFF; /* &y */ + if (IntVal(amperY) >= 0x8000) + IntVal(amperY) -= 0x10000; + IntVal(amperX) -= w->context->dx; + IntVal(amperY) -= w->context->dy; + MakeInt(1 + XTOCOL(w,IntVal(amperX)), &(amperCol)); /* &col */ + MakeInt(YTOROW(w,IntVal(amperY)) , &(amperRow)); /* &row */ + + xmod_control = IntVal(xdesc) & EQ_MOD_CONTROL; /* &control */ + xmod_meta = IntVal(xdesc) & EQ_MOD_META; /* &meta */ + xmod_shift = IntVal(xdesc) & EQ_MOD_SHIFT; /* &shift */ + + i = (((uword) IntVal(ydesc)) >> 16) & 0xFFF; /* mantissa */ + i <<= 4 * ((((uword) IntVal(ydesc)) >> 28) & 0x7); /* scale it */ + IntVal(amperInterval) = i; /* &interval */ + return 0; + } + +/* + * get event from window (drop mouse events), no echo + * + * return: 1 = success, -1 = window died, -2 = malformed queue, -3 = EOF + */ +int wgetchne(w,res) +wbp w; +dptr res; + { + int i; + + while (1) { + i = wgetevent(w,res); + if (i != 0) + return i; + if (is:string(*res)) { +#ifdef WinGraphics + if (*StrLoc(*res) == '\032') return -3; /* control-Z gives EOF */ +#endif /* WinGraphics */ + return 1; + } + } + } + +/* + * get event from window (drop mouse events), with echo + * + * returns 1 for success, -1 if window died, -2 for malformed queue, -3 for EOF + */ +int wgetche(w,res) +wbp w; +dptr res; + { + int i; + i = wgetchne(w,res); + if (i != 1) + return i; + i = *StrLoc(*res); + if ((0 <= i) && (i <= 127) && (ISECHOON(w))) { + wputc(i, w); + if (i == '\r') wputc((int)'\n', w); /* CR -> CR/LF */ + } + return 1; + } + +/* + * Get a window that has an event pending (queued) + */ +wsp getactivewindow() + { + static LONG next = 0; + LONG i, j, nwindows = 0; + wsp ptr, ws, stdws = NULL; + extern FILE *ConsoleBinding; + + if (wstates == NULL) return NULL; + for(ws = wstates; ws; ws=ws->next) nwindows++; + if (ConsoleBinding) stdws = ((wbp)ConsoleBinding)->window; + /* + * make sure we are still in bounds + */ + next %= nwindows; + /* + * position ptr on the next window to get events from + */ + for (ptr = wstates, i = 0; i < next; i++, ptr = ptr->next); + /* + * Infinite loop, checking for an event somewhere, sleeping awhile + * each iteration. + */ + for (;;) { + /* + * Check for any new pending events. + */ + switch (pollevent()) { + case -1: ReturnErrNum(141, NULL); + case 0: return NULL; + } + /* + * go through windows, looking for one with an event pending + */ + for (ws = ptr, i = 0, j = next + 1; i < nwindows; + (ws = (ws->next) ? ws->next : wstates), i++, j++) + if (ws != stdws && BlkLoc(ws->listp)->list.size > 0) { + next = j; + return ws; + } + /* + * couldn't find a pending event - wait awhile + */ + idelay(POLLSLEEP); + } + } + +/* + * wlongread(s,elsize,nelem,f) -- read string from window for reads(w) + * + * returns length(>=0) for success, -1 if window died, -2 for malformed queue + * -3 on EOF + */ +int wlongread(s, elsize, nelem, f) +char *s; +int elsize, nelem; +FILE *f; + { + int c; + tended char *ts = s; + struct descrip foo; + long l = 0, bytes = elsize * nelem; + + while (l < bytes) { + c = wgetche((wbp)f, &foo); + if (c == -3 && l > 0) + return l; + if (c < 0) + return c; + c = *StrLoc(foo); + switch(c) { + case '\177': + case '\010': + if (l > 0) { ts--; l--; } + break; + default: + *ts++ = c; l++; + break; + } + } + return l; + } + +/* + * wgetstrg(s,maxlen,f) -- get string from window for read(w) or !w + * + * returns length(>=0) for success, -1 if window died, -2 for malformed queue + * -3 for EOF, -4 if length was limited by maxi + */ +int wgetstrg(s, maxlen, f) +char *s; +long maxlen; +FILE *f; + { + int c; + tended char *ts = s; + long l = 0; + struct descrip foo; + + while (l < maxlen) { + c = wgetche((wbp)f,&foo); + if (c == -3 && l > 0) + return l; + if (c < 0) + return c; + c = *StrLoc(foo); + switch(c) { + case '\177': + case '\010': + if (l > 0) { ts--; l--; } + break; + case '\r': + case '\n': + return l; + default: + *ts++ = c; l++; + break; + } + } + return -4; + } + + +/* + * Assignment side-effects for &x,&y,&row,&col + */ +int xyrowcol(dx) +dptr dx; +{ + if (VarLoc(*dx) == &erX) { /* update &col too */ + wbp w; + if (!is:file(lastEventWin) || + ((BlkLoc(lastEventWin)->file.status & Fs_Window) == 0) || + ((BlkLoc(lastEventWin)->file.status & (Fs_Read|Fs_Write)) == 0)) { + MakeInt(1 + IntVal(amperX)/lastEvFWidth, &erCol); + } + else { + w = (wbp)BlkLoc(lastEventWin)->file.fd; + MakeInt(1 + XTOCOL(w, IntVal(amperX)), &erCol); + } + } + else if (VarLoc(*dx) == &erY) { /* update &row too */ + wbp w; + if (!is:file(lastEventWin) || + ((BlkLoc(lastEventWin)->file.status & Fs_Window) == 0) || + ((BlkLoc(lastEventWin)->file.status & (Fs_Read|Fs_Write)) == 0)) { + MakeInt(IntVal(amperY) / lastEvLeading + 1, &erRow); + } + else { + w = (wbp)BlkLoc(lastEventWin)->file.fd; + MakeInt(YTOROW(w, IntVal(amperY)), &erRow); + } + } + else if (VarLoc(*dx) == &erCol) { /* update &x too */ + wbp w; + if (!is:file(lastEventWin) || + ((BlkLoc(lastEventWin)->file.status & Fs_Window) == 0) || + ((BlkLoc(lastEventWin)->file.status & (Fs_Read|Fs_Write)) == 0)) { + MakeInt((IntVal(amperCol) - 1) * lastEvFWidth, &erX); + } + else { + w = (wbp)BlkLoc(lastEventWin)->file.fd; + MakeInt(COLTOX(w, IntVal(amperCol)), &erX); + } + } + else if (VarLoc(*dx) == &erRow) { /* update &y too */ + wbp w; + if (!is:file(lastEventWin) || + ((BlkLoc(lastEventWin)->file.status & Fs_Window) == 0) || + ((BlkLoc(lastEventWin)->file.status & (Fs_Read|Fs_Write)) == 0)) { + MakeInt((IntVal(amperRow)-1) * lastEvLeading + lastEvAscent, &erY); + } + else { + w = (wbp)BlkLoc(lastEventWin)->file.fd; + MakeInt(ROWTOY(w, IntVal(amperRow)), &erY); + } + } + return 0; + } + + +/* + * Enqueue an event, encoding time interval and key state with x and y values. + */ +void qevent(ws,e,x,y,t,f) +wsp ws; /* canvas */ +dptr e; /* event code (descriptor pointer) */ +int x, y; /* x and y values */ +uword t; /* ms clock value */ +long f; /* modifier key flags */ + { + dptr q = &(ws->listp); /* a window's event queue (Icon list value) */ + struct descrip d; + uword ivl, mod; + int expo; + + mod = 0; /* set modifier key bits */ + if (f & ControlMask) mod |= EQ_MOD_CONTROL; + if (f & Mod1Mask) mod |= EQ_MOD_META; + if (f & ShiftMask) mod |= EQ_MOD_SHIFT; + + if (t != ~(uword)0) { /* if clock value supplied */ + if (ws->timestamp == 0) /* if first time */ + ws->timestamp = t; + if (t < ws->timestamp) /* if clock went backwards */ + t = ws->timestamp; + ivl = t - ws->timestamp; /* calc interval in milliseconds */ + ws->timestamp = t; /* save new clock value */ + expo = 0; + while (ivl >= 0x1000) { /* if too big */ + ivl >>= 4; /* reduce significance */ + expo += 0x1000; /* bump exponent */ + } + ivl += expo; /* combine exponent with mantissa */ + } + else + ivl = 0; /* report 0 if interval unknown */ + + c_put(q, e); + d.dword = D_Integer; + IntVal(d) = mod | (x & 0xFFFF); + c_put(q, &d); + IntVal(d) = (ivl << 16) | (y & 0xFFFF); + c_put(q, &d); + } + +/* + * setpos() - set (move) canvas position on the screen + */ +static int setpos(w,s) +wbp w; +char *s; + { + char *s2, tmp[32]; + int posx, posy; + + s2 = s; + while (isspace(*s2)) s2++; + if (!isdigit(*s2) && (*s2 != '-')) return Error; + posx = atol(s2); + if (*s2 == '-') s2++; + while (isdigit(*s2)) s2++; + if (*s2 == '.') { + s2++; + while (isdigit(*s2)) s2++; + } + if (*s2++ != ',') return Error; + if (!isdigit(*s2) && (*s2 != '-')) return Error; + posy = atol(s2); + if (*s2 == '-') s2++; + while (isdigit(*s2)) s2++; + if (*s2 == '.') { + s2++; + while (isdigit(*s2)) s2++; + } + if (*s2) return Error; + if (posx < 0) { + if (posy < 0) sprintf(tmp,"%d%d",posx,posy); + else sprintf(tmp,"%d+%d",posx,posy); + } + else { + if (posy < 0) sprintf(tmp,"+%d%d",posx,posy); + else sprintf(tmp,"+%d+%d",posx,posy); + } + return setgeometry(w,tmp); + } + +/* + * setsize() - set canvas size + */ +int setsize(w,s) +wbp w; +char *s; + { + char *s2, tmp[32]; + int width, height; + + s2 = s; + while (isspace(*s2)) s2++; + if (!isdigit(*s2) && (*s2 != '-')) return Error; + width = atol(s2); + if (*s2 == '-') s2++; + while (isdigit(*s2)) s2++; + if (*s2 == '.') { + s2++; + while (isdigit(*s2)) s2++; + } + if (*s2++ != ',') return Error; + height = atol(s2); + if (*s2 == '-') s2++; + while (isdigit(*s2)) s2++; + if (*s2 == '.') { + s2++; + while (isdigit(*s2)) s2++; + } + if (*s2) return Error; + sprintf(tmp,"%dx%d",width,height); + return setgeometry(w,tmp); + } + + + +/* + * put a string out to a window using the current attributes + */ +void wputstr(w,s,len) +wbp w; +char *s; +int len; + { + char *s2 = s; + wstate *ws = w->window; + /* turn off the cursor */ + hidecrsr(ws); + + while (len > 0) { + /* + * find a chunk of printable text + */ +#ifdef WinGraphics + while (len > 0) { + if (IsDBCSLeadByte(*s2)) { + s2++; s2++; len--; len--; + } + else if (isprint(*s2)) { + s2++; len--; + } + else break; + } +#else /* WinGraphics */ + while (isprint(*s2) && len > 0) { + s2++; len--; + } +#endif /* WinGraphics */ + /* + * if a chunk was parsed, write it out + */ + if (s2 != s) + xdis(w, s, s2 - s); + /* + * put the 'unprintable' character, if didn't just hit the end + */ + if (len-- > 0) { + wputc(*s2++, w); + } + s = s2; + } + + /* show the cursor again */ + UpdateCursorPos(ws, w->context); + showcrsr(ws); + return; +} + +/* + * mapping from recognized style attributes to flag values + */ +stringint fontwords[] = { + { 0, 17 }, /* number of entries */ + { "bold", FONTATT_WEIGHT | FONTFLAG_BOLD }, + { "condensed", FONTATT_WIDTH | FONTFLAG_CONDENSED }, + { "demi", FONTATT_WEIGHT | FONTFLAG_DEMI }, + { "demibold", FONTATT_WEIGHT | FONTFLAG_DEMI | FONTFLAG_BOLD }, + { "extended", FONTATT_WIDTH | FONTFLAG_EXTENDED }, + { "italic", FONTATT_SLANT | FONTFLAG_ITALIC }, + { "light", FONTATT_WEIGHT | FONTFLAG_LIGHT }, + { "medium", FONTATT_WEIGHT | FONTFLAG_MEDIUM }, + { "mono", FONTATT_SPACING | FONTFLAG_MONO }, + { "narrow", FONTATT_WIDTH | FONTFLAG_NARROW }, + { "normal", FONTATT_WIDTH | FONTFLAG_NORMAL }, + { "oblique", FONTATT_SLANT | FONTFLAG_OBLIQUE }, + { "proportional", FONTATT_SPACING | FONTFLAG_PROPORTIONAL }, + { "roman", FONTATT_SLANT | FONTFLAG_ROMAN }, + { "sans", FONTATT_SERIF | FONTFLAG_SANS }, + { "serif", FONTATT_SERIF | FONTFLAG_SERIF }, + { "wide", FONTATT_WIDTH | FONTFLAG_WIDE }, +}; + +/* + * parsefont - extract font family name, style attributes, and size + * + * these are window system independent values, so they require + * further translation into window system dependent values. + * + * returns 1 on an OK font name + * returns 0 on a "malformed" font (might be a window-system fontname) + */ +int parsefont(s, family, style, size) +char *s; +char family[MAXFONTWORD+1]; +int *style; +int *size; + { + char c, *a, attr[MAXFONTWORD+1]; + int tmp; + + /* + * set up the defaults + */ + *family = '\0'; + *style = 0; + *size = -1; + + /* + * now, scan through the raw and break out pieces + */ + for (;;) { + + /* + * find start of next comma-separated attribute word + */ + while (isspace(*s) || *s == ',') /* trim leading spaces & empty words */ + s++; + if (*s == '\0') /* stop at end of string */ + break; + + /* + * copy word, converting to lower case to implement case insensitivity + */ + for (a = attr; (c = *s) != '\0' && c != ','; s++) { + if (isupper(c)) + c = tolower(c); + *a++ = c; + if (a - attr >= MAXFONTWORD) + return 0; /* too long */ + } + + /* + * trim trailing spaces and terminate word + */ + while (isspace(a[-1])) + a--; + *a = '\0'; + + /* + * interpret word as family name, size, or style characteristic + */ + if (*family == '\0') + strcpy(family, attr); /* first word is the family name */ + + else if (sscanf(attr, "%d%c", &tmp, &c) == 1 && tmp > 0) { + if (*size != -1 && *size != tmp) + return 0; /* if conflicting sizes given */ + *size = tmp; /* integer value is a size */ + } + + else { /* otherwise it's a style attribute */ + tmp = si_s2i(fontwords, attr); /* look up in table */ + if (tmp != -1) { /* if recognized */ + if ((tmp & *style) != 0 && (tmp & *style) != tmp) + return 0; /* conflicting attribute */ + *style |= tmp; + } + } + } + + /* got to end of string; it's OK if it had at least a font family */ + return (*family != '\0'); + } + +/* + * parsepattern() - parse an encoded numeric stipple pattern + */ +int parsepattern(s, len, width, nbits, bits) +char *s; +int len; +int *width, *nbits; +C_integer *bits; + { + C_integer v; + int i, j, hexdigits_per_row, maxbits = *nbits; + + /* + * Get the width + */ + if (sscanf(s, "%d,", width) != 1) return Error; + if (*width < 1) return Failed; + + /* + * skip over width + */ + while ((len > 0) && isdigit(*s)) { + len--; s++; + } + if ((len <= 1) || (*s != ',')) return Error; + len--; s++; /* skip over ',' */ + + if (*s == '#') { + /* + * get remaining bits as hex constant + */ + s++; len--; + if (len == 0) return Error; + hexdigits_per_row = *width / 4; + if (*width % 4) hexdigits_per_row++; + *nbits = len / hexdigits_per_row; + if (len % hexdigits_per_row) (*nbits)++; + if (*nbits > maxbits) return Failed; + for (i = 0; i < *nbits; i++) { + v = 0; + for (j = 0; j < hexdigits_per_row; j++, len--, s++) { + if (len == 0) break; + v <<= 4; + if (isdigit(*s)) v += *s - '0'; + else switch (*s) { + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + v += *s - 'a' + 10; break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + v += *s - 'A' + 10; break; + default: return Error; + } + } + *bits++ = v; + } + } + else { + if (*width > 32) return Failed; + /* + * get remaining bits as comma-separated decimals + */ + v = 0; + *nbits = 0; + while (len > 0) { + while ((len > 0) && isdigit(*s)) { + v = v * 10 + *s - '0'; + len--; s++; + } + (*nbits)++; + if (*nbits > maxbits) return Failed; + *bits++ = v; + v = 0; + + if (len > 0) { + if (*s == ',') { len--; s++; } + else { + ReturnErrNum(205, Error); + } + } + } + } + return Succeeded; + } + +/* + * parsegeometry - parse a string of the form: intxint[+-]int[+-]int + * Returns: + * 0 on bad value, 1 if size is set, 2 if position is set, 3 if both are set + */ +int parsegeometry(buf, x, y, width, height) +char *buf; +SHORT *x, *y, *width, *height; + { + int retval = 0; + if (isdigit(*buf)) { + retval++; + if ((*width = atoi(buf)) <= 0) return 0; + while (isdigit(*++buf)); + if (*buf++ != 'x') return 0; + if ((*height = atoi(buf)) <= 0) return 0; + while (isdigit(*++buf)); + } + + if (*buf == '+' || *buf == '-') { + retval += 2; + *x = atoi(buf); + buf++; /* skip over +/- */ + while (isdigit(*buf)) buf++; + + if (*buf != '+' && *buf != '-') return 0; + *y = atoi(buf); + buf++; /* skip over +/- */ + while (isdigit(*buf)) buf++; + if (*buf) return 0; + } + return retval; + } + + +/* return failure if operation returns either failure or error */ +#define AttemptAttr(operation) if ((operation) != Succeeded) return Failed; + +/* does string (already checked for "on" or "off") say "on"? */ +#define ATOBOOL(s) (s[1]=='n') + +/* + * Attribute manipulation + * + * wattrib() - get/set a single attribute in a window, return the result attr + * string. + */ +int wattrib(w, s, len, answer, abuf) +wbp w; +char *s; +long len; +dptr answer; +char * abuf; + { + char val[128], *valptr; + struct descrip d; + char *mid, *midend, c; + int r, a; + C_integer tmp; + long lenattr, lenval; + double gamma; + SHORT new_height, new_width; + wsp ws = w->window; + wcp wc = w->context; + + valptr = val; + /* + * catch up on any events pending - mainly to update pointerx, pointery + */ + if (pollevent() == -1) + fatalerr(141,NULL); + + midend = s + len; + for (mid = s; mid < midend; mid++) + if (*mid == '=') break; + + if (mid < midend) { + /* + * set an attribute + */ + lenattr = mid - s; + lenval = len - lenattr - 1; + mid++; + + strncpy(abuf, s, lenattr); + abuf[lenattr] = '\0'; + strncpy(val, mid, lenval); + val[lenval] = '\0'; + StrLen(d) = strlen(val); + StrLoc(d) = val; + + switch (a = si_s2i(attribs, abuf)) { + case A_LINES: case A_ROWS: { + if (!cnv:C_integer(d, tmp)) + return Failed; + if ((new_height = tmp) < 1) + return Failed; + new_height = ROWTOY(w, new_height); + new_height += MAXDESCENDER(w); + if (setheight(w, new_height) == Failed) return Failed; + break; + } + case A_COLUMNS: { + if (!cnv:C_integer(d, tmp)) + return Failed; + if ((new_width = tmp) < 1) + return Failed; + new_width = COLTOX(w, new_width + 1); + if (setwidth(w, new_width) == Failed) return Failed; + break; + } + case A_HEIGHT: { + if (!cnv:C_integer(d, tmp)) + return Failed; + if ((new_height = tmp) < 1) return Failed; + if (setheight(w, new_height) == Failed) return Failed; + break; + } + case A_WIDTH: { + if (!cnv:C_integer(d, tmp)) + return Failed; + if ((new_width = tmp) < 1) return Failed; + if (setwidth(w, new_width) == Failed) return Failed; + break; + } + case A_SIZE: { + AttemptAttr(setsize(w, val)); + break; + } + case A_GEOMETRY: { + AttemptAttr(setgeometry(w, val)); + break; + } + case A_RESIZE: { + if (strcmp(val, "on") & strcmp(val, "off")) + return Failed; + allowresize(w, ATOBOOL(val)); + break; + } + case A_ROW: { + if (!cnv:C_integer(d, tmp)) + return Failed; + ws->y = ROWTOY(w, tmp) + wc->dy; + break; + } + case A_COL: { + if (!cnv:C_integer(d, tmp)) + return Failed; + ws->x = COLTOX(w, tmp) + wc->dx; + break; + } + case A_CANVAS: { + AttemptAttr(setcanvas(w,val)); + break; + } + case A_ICONIC: { + AttemptAttr(seticonicstate(w,val)); + break; + } + case A_ICONIMAGE: { + if (!val[0]) return Failed; + AttemptAttr(seticonimage(w, &d)); + break; + } + case A_ICONLABEL: { + AttemptAttr(seticonlabel(w, val)); + break; + } + case A_ICONPOS: { + AttemptAttr(seticonpos(w,val)); + break; + } + case A_LABEL: + case A_WINDOWLABEL: { + AttemptAttr(setwindowlabel(w, val)); + break; + } + case A_CURSOR: { + int on_off; + if (strcmp(val, "on") & strcmp(val, "off")) + return Failed; + on_off = ATOBOOL(val); + setcursor(w, on_off); + break; + } + case A_FONT: { + AttemptAttr(setfont(w, &valptr)); + break; + } + case A_PATTERN: { + AttemptAttr(SetPattern(w, val, strlen(val))); + break; + } + case A_POS: { + AttemptAttr(setpos(w, val)); + break; + } + case A_POSX: { + char tmp[20]; + sprintf(tmp,"%s,%d",val,ws->posy); + AttemptAttr(setpos(w, tmp)); + break; + } + case A_POSY: { + char tmp[20]; + sprintf(tmp,"%d,%s",ws->posx,val); + AttemptAttr(setpos(w, tmp)); + break; + } + case A_FG: { + if (cnv:C_integer(d, tmp) && tmp < 0) { + if (isetfg(w, tmp) != Succeeded) return Failed; + } + else { + if (setfg(w, val) != Succeeded) return Failed; + } + break; + } + case A_BG: { + if (cnv:C_integer(d, tmp) && tmp < 0) { + if (isetbg(w, tmp) != Succeeded) return Failed; + } + else { + if (setbg(w, val) != Succeeded) return Failed; + } + break; + } + case A_GAMMA: { + if (sscanf(val, "%lf%c", &gamma, &c) != 1 || gamma <= 0.0) + return Failed; + if (setgamma(w, gamma) != Succeeded) + return Failed; + break; + } + case A_FILLSTYLE: { + AttemptAttr(setfillstyle(w, val)); + break; + } + case A_LINESTYLE: { + AttemptAttr(setlinestyle(w, val)); + break; + } + case A_LINEWIDTH: { + if (!cnv:C_integer(d, tmp)) + return Failed; + if (setlinewidth(w, tmp) == Error) + return Failed; + break; + } + case A_POINTER: { + AttemptAttr(setpointer(w, val)); + break; + } + case A_DRAWOP: { + AttemptAttr(setdrawop(w, val)); + break; + } + case A_DISPLAY: { + AttemptAttr(setdisplay(w,val)); + break; + } + case A_X: { + if (!cnv:C_integer(d, tmp)) + return Failed; + ws->x = tmp + wc->dx; + UpdateCursorPos(ws, wc); /* tell system where to blink it */ + break; + } + case A_Y: { + if (!cnv:C_integer(d, tmp)) + return Failed; + ws->y = tmp + wc->dy; + UpdateCursorPos(ws, wc); /* tell system where to blink it */ + break; + } + case A_DX: { + if (!cnv:C_integer(d, tmp)) + return Failed; + wc->dx = tmp; + UpdateCursorPos(ws, wc); /* tell system where to blink it */ + break; + } + case A_DY: { + if (!cnv:C_integer(d, tmp)) + return Failed; + wc->dy = tmp; + UpdateCursorPos(ws, wc); /* tell system where to blink it */ + break; + } + case A_LEADING: { + if (!cnv:C_integer(d, tmp)) + return Failed; + setleading(w, tmp); + break; + } + case A_IMAGE: { + /* first try GIF; then try platform-dependent format */ + r = readGIF(val, 0, &ws->initimage); + if (r == Succeeded) { + setwidth(w, ws->initimage.width); + setheight(w, ws->initimage.height); + } + else + r = setimage(w, val); + AttemptAttr(r); + break; + } + case A_ECHO: { + if (strcmp(val, "on") & strcmp(val, "off")) + return Failed; + if (ATOBOOL(val)) SETECHOON(w); + else CLRECHOON(w); + break; + } + case A_CLIPX: + case A_CLIPY: + case A_CLIPW: + case A_CLIPH: { + if (!*val) { + wc->clipx = wc->clipy = 0; + wc->clipw = wc->cliph = -1; + unsetclip(w); + } + else { + if (!cnv:C_integer(d, tmp)) + return Failed; + if (wc->clipw < 0) { + wc->clipx = wc->clipy = 0; + wc->clipw = ws->width; + wc->cliph = ws->height; + } + switch (a) { + case A_CLIPX: wc->clipx = tmp; break; + case A_CLIPY: wc->clipy = tmp; break; + case A_CLIPW: wc->clipw = tmp; break; + case A_CLIPH: wc->cliph = tmp; break; + } + setclip(w); + } + break; + } + case A_REVERSE: { + if (strcmp(val, "on") && strcmp(val, "off")) + return Failed; + if ((!ATOBOOL(val) && ISREVERSE(w)) || + (ATOBOOL(val) && !ISREVERSE(w))) { + toggle_fgbg(w); + ISREVERSE(w) ? CLRREVERSE(w) : SETREVERSE(w); + } + break; + } + case A_POINTERX: { + if (!cnv:C_integer(d, tmp)) + return Failed; + ws->pointerx = tmp + wc->dx; + warpPointer(w, ws->pointerx, ws->pointery); + break; + } + case A_POINTERY: { + if (!cnv:C_integer(d, tmp)) + return Failed; + ws->pointery = tmp + wc->dy; + warpPointer(w, ws->pointerx, ws->pointery); + break; + } + case A_POINTERCOL: { + if (!cnv:C_integer(d, tmp)) + return Failed; + ws->pointerx = COLTOX(w, tmp) + wc->dx; + warpPointer(w, ws->pointerx, ws->pointery); + break; + } + case A_POINTERROW: { + if (!cnv:C_integer(d, tmp)) + return Failed; + ws->pointery = ROWTOY(w, tmp) + wc->dy; + warpPointer(w, ws->pointerx, ws->pointery); + break; + } + /* + * remaining valid attributes are error #147 + */ + case A_DEPTH: + case A_DISPLAYHEIGHT: + case A_DISPLAYWIDTH: + case A_FHEIGHT: + case A_FWIDTH: + case A_ASCENT: + case A_DESCENT: + ReturnErrNum(147, Error); + /* + * invalid attribute + */ + default: + ReturnErrNum(145, Error); + } + strncpy(abuf, s, len); + abuf[len] = '\0'; + } + else { + int a; + /* + * get an attribute + */ + strncpy(abuf, s, len); + abuf[len] = '\0'; + switch (a=si_s2i(attribs, abuf)) { + case A_IMAGE: + ReturnErrNum(147, Error); + case A_VISUAL: + if (getvisual(w, abuf) == Failed) return Failed; + MakeStr(abuf, strlen(abuf), answer); + break; + case A_DEPTH: + MakeInt(SCREENDEPTH(w), answer); + break; + case A_DISPLAY: + getdisplay(w, abuf); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_ASCENT: + MakeInt(ASCENT(w), answer); + break; + case A_DESCENT: + MakeInt(DESCENT(w), answer); + break; + case A_FHEIGHT: + MakeInt(FHEIGHT(w), answer); + break; + case A_FWIDTH: + MakeInt(FWIDTH(w), answer); + break; + case A_ROW: + MakeInt(YTOROW(w, ws->y - wc->dy), answer); + break; + case A_COL: + MakeInt(1 + XTOCOL(w, ws->x - wc->dx), answer); + break; + case A_POINTERROW: { + XPoint xp; + query_pointer(w, &xp); + MakeInt(YTOROW(w, xp.y - wc->dy), answer); + break; + } + case A_POINTERCOL: { + XPoint xp; + query_pointer(w, &xp); + MakeInt(1 + XTOCOL(w, xp.x - wc->dx), answer); + break; + } + case A_LINES: + case A_ROWS: + MakeInt(YTOROW(w,ws->height - DESCENT(w)), answer); + break; + case A_COLUMNS: + MakeInt(XTOCOL(w,ws->width), answer); + break; + case A_POS: case A_POSX: case A_POSY: + if (getpos(w) == Failed) + return Failed; + switch (a) { + case A_POS: + sprintf(abuf, "%d,%d", ws->posx, ws->posy); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_POSX: + MakeInt(ws->posx, answer); + break; + case A_POSY: + MakeInt(ws->posy, answer); + break; + } + break; + case A_FG: + getfg(w, abuf); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_BG: + getbg(w, abuf); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_GAMMA: + Protect(BlkLoc(*answer) = (union block *)alcreal(wc->gamma), + return Error); + answer->dword = D_Real; + break; + case A_FILLSTYLE: + sprintf(abuf, "%s", + (wc->fillstyle == FS_SOLID) ? "solid" : + (wc->fillstyle == FS_STIPPLE) ? "masked" : "textured"); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_LINESTYLE: + getlinestyle(w, abuf); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_LINEWIDTH: + MakeInt(LINEWIDTH(w), answer); + break; + case A_HEIGHT: { MakeInt(ws->height, answer); break; } + case A_WIDTH: { MakeInt(ws->width, answer); break; } + case A_SIZE: + sprintf(abuf, "%d,%d", ws->width, ws->height); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_RESIZE: + sprintf(abuf,"%s",(ISRESIZABLE(w)?"on":"off")); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_DISPLAYHEIGHT: + MakeInt(DISPLAYHEIGHT(w), answer); + break; + case A_DISPLAYWIDTH: + MakeInt(DISPLAYWIDTH(w), answer); + break; + case A_CURSOR: + sprintf(abuf,"%s",(ISCURSORON(w)?"on":"off")); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_ECHO: + sprintf(abuf,"%s",(ISECHOON(w)?"on":"off")); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_REVERSE: + sprintf(abuf,"%s",(ISREVERSE(w)?"on":"off")); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_FONT: + getfntnam(w, abuf); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_X: MakeInt(ws->x - wc->dx, answer); break; + case A_Y: MakeInt(ws->y - wc->dy, answer); break; + case A_DX: MakeInt(wc->dx, answer); break; + case A_DY: MakeInt(wc->dy, answer); break; + case A_LEADING: MakeInt(LEADING(w), answer); break; + case A_POINTERX: { + XPoint xp; + query_pointer(w, &xp); + MakeInt(xp.x - wc->dx, answer); + break; + } + case A_POINTERY: { + XPoint xp; + query_pointer(w, &xp); + MakeInt(xp.y - wc->dy, answer); + break; + } + case A_POINTER: + getpointername(w, abuf); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_DRAWOP: + getdrawop(w, abuf); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_GEOMETRY: + if (getpos(w) == Failed) return Failed; + if (ws->win) + sprintf(abuf, "%dx%d+%d+%d", + ws->width, ws->height, ws->posx, ws->posy); + else + sprintf(abuf, "%dx%d", ws->pixwidth, ws->pixheight); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_CANVAS: + getcanvas(w, abuf); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_ICONIC: + geticonic(w, abuf); + MakeStr(abuf, strlen(abuf), answer); + break; + case A_ICONIMAGE: + if (ICONFILENAME(w) != NULL) + sprintf(abuf, "%s", ICONFILENAME(w)); + else *abuf = '\0'; + MakeStr(abuf, strlen(abuf), answer); + break; + case A_ICONLABEL: + if (ICONLABEL(w) != NULL) + sprintf(abuf, "%s", ICONLABEL(w)); + else return Failed; + MakeStr(abuf, strlen(abuf), answer); + break; + case A_LABEL: + case A_WINDOWLABEL: + if (WINDOWLABEL(w) != NULL) + sprintf(abuf,"%s", WINDOWLABEL(w)); + else return Failed; + MakeStr(abuf, strlen(abuf), answer); + break; + case A_ICONPOS: { + switch (geticonpos(w,abuf)) { + case Failed: return Failed; + case Error: return Failed; + } + MakeStr(abuf, strlen(abuf), answer); + break; + } + case A_PATTERN: { + s = w->context->patternname; + if (s != NULL) + MakeStr(s, strlen(s), answer); + else + MakeStr("black", 5, answer); + break; + } + case A_CLIPX: + if (wc->clipw >= 0) + MakeInt(wc->clipx, answer); + else + *answer = nulldesc; + break; + case A_CLIPY: + if (wc->clipw >= 0) + MakeInt(wc->clipy, answer); + else + *answer = nulldesc; + break; + case A_CLIPW: + if (wc->clipw >= 0) + MakeInt(wc->clipw, answer); + else + *answer = nulldesc; + break; + case A_CLIPH: + if (wc->clipw >= 0) + MakeInt(wc->cliph, answer); + else + *answer = nulldesc; + break; + default: + ReturnErrNum(145, Error); + } + } + wflush(w); + return Succeeded; + } + +/* + * rectargs -- interpret rectangle arguments uniformly + * + * Given an arglist and the index of the next x value, rectargs sets + * x/y/width/height to explicit or defaulted values. These result values + * are in canonical form: Width and height are nonnegative and x and y + * have been corrected by dx and dy. + * + * Returns index of bad argument, if any, or -1 for success. + */ +int rectargs(w, argc, argv, i, px, py, pw, ph) +wbp w; +int argc; +dptr argv; +int i; +C_integer *px, *py, *pw, *ph; + { + int defw, defh; + wcp wc = w->context; + wsp ws = w->window; + + /* + * Get x and y, defaulting to -dx and -dy. + */ + if (i >= argc) + *px = -wc->dx; + else if (!def:C_integer(argv[i], -wc->dx, *px)) + return i; + + if (++i >= argc) + *py = -wc->dy; + else if (!def:C_integer(argv[i], -wc->dy, *py)) + return i; + + *px += wc->dx; + *py += wc->dy; + + /* + * Get w and h, defaulting to extend to the edge + */ + defw = ws->width - *px; + defh = ws->height - *py; + + if (++i >= argc) + *pw = defw; + else if (!def:C_integer(argv[i], defw, *pw)) + return i; + + if (++i >= argc) + *ph = defh; + else if (!def:C_integer(argv[i], defh, *ph)) + return i; + + /* + * Correct negative w/h values. + */ + if (*pw < 0) + *px -= (*pw = -*pw); + if (*ph < 0) + *py -= (*ph = -*ph); + + return -1; + } + +/* + * docircles -- draw or file circles. + * + * Helper for DrawCircle and FillCircle. + * Returns index of bad argument, or -1 for success. + */ +int docircles(w, argc, argv, fill) +wbp w; +int argc; +dptr argv; +int fill; + { + XArc arc; + int i, dx, dy; + double x, y, r, theta, alpha; + + dx = w->context->dx; + dy = w->context->dy; + + for (i = 0; i < argc; i += 5) { /* for each set of five args */ + + /* + * Collect arguments. + */ + if (i + 2 >= argc) + return i + 2; /* missing y or r */ + if (!cnv:C_double(argv[i], x)) + return i; + if (!cnv:C_double(argv[i + 1], y)) + return i + 1; + if (!cnv:C_double(argv[i + 2], r)) + return i + 2; + if (i + 3 >= argc) + theta = 0.0; + else if (!def:C_double(argv[i + 3], 0.0, theta)) + return i + 3; + if (i + 4 >= argc) + alpha = 2 * Pi; + else if (!def:C_double(argv[i + 4], 2 * Pi, alpha)) + return i + 4; + + /* + * Put in canonical form: r >= 0, -2*pi <= theta < 0, alpha >= 0. + */ + if (r < 0) { /* ensure positive radius */ + r = -r; + theta += Pi; + } + if (alpha < 0) { /* ensure positive extent */ + theta += alpha; + alpha = -alpha; + } + + theta = fmod(theta, 2 * Pi); + if (theta > 0) /* normalize initial angle */ + theta -= 2 * Pi; + + /* + * Build the Arc descriptor. + */ + arc.x = x + dx - r; + arc.y = y + dy - r; + ARCWIDTH(arc) = 2 * r; + ARCHEIGHT(arc) = 2 * r; + + arc.angle1 = ANGLE(theta); + if (alpha >= 2 * Pi) + arc.angle2 = EXTENT(2 * Pi); + else + arc.angle2 = EXTENT(alpha); + + /* + * Draw or fill the arc. + */ + if (fill) { /* {} required due to form of macros */ + fillarcs(w, &arc, 1); + } + else { + drawarcs(w, &arc, 1); + } + } + return -1; + } + + +/* + * genCurve - draw a smooth curve through a set of points. Algorithm from + * Barry, Phillip J., and Goldman, Ronald N. (1988). + * A Recursive Evaluation Algorithm for a class of Catmull-Rom Splines. + * Computer Graphics 22(4), 199-204. + */ +void genCurve(w, p, n, helper) +wbp w; +XPoint *p; +int n; +void (*helper) (wbp, XPoint [], int); + { + int i, j, steps; + float ax, ay, bx, by, stepsize, stepsize2, stepsize3; + float x, dx, d2x, d3x, y, dy, d2y, d3y; + XPoint *thepoints = NULL; + long npoints = 0; + + for (i = 3; i < n; i++) { + /* + * build the coefficients ax, ay, bx and by, using: + * _ _ _ _ + * i i 1 | -1 3 -3 1 | | Pi-3 | + * Q (t) = T * M * G = - | 2 -5 4 -1 | | Pi-2 | + * CR Bs 2 | -1 0 1 0 | | Pi-1 | + * |_ 0 2 0 0_| |_Pi _| + */ + + ax = p[i].x - 3 * p[i-1].x + 3 * p[i-2].x - p[i-3].x; + ay = p[i].y - 3 * p[i-1].y + 3 * p[i-2].y - p[i-3].y; + bx = 2 * p[i-3].x - 5 * p[i-2].x + 4 * p[i-1].x - p[i].x; + by = 2 * p[i-3].y - 5 * p[i-2].y + 4 * p[i-1].y - p[i].y; + + /* + * calculate the forward differences for the function using + * intervals of size 0.1 + */ +#ifndef abs +#define abs(x) ((x)<0?-(x):(x)) +#endif +#ifndef max +#define max(x,y) ((x>y)?x:y) +#endif + + steps = max(abs(p[i-1].x - p[i-2].x), abs(p[i-1].y - p[i-2].y)) + 10; + if (steps+4 > npoints) { + if (thepoints != NULL) free(thepoints); + thepoints = malloc((steps+4) * sizeof(XPoint)); + npoints = steps+4; + } + + stepsize = 1.0/steps; + stepsize2 = stepsize * stepsize; + stepsize3 = stepsize * stepsize2; + + x = thepoints[0].x = p[i-2].x; + y = thepoints[0].y = p[i-2].y; + dx = (stepsize3*0.5)*ax + (stepsize2*0.5)*bx + (stepsize*0.5)*(p[i-1].x-p[i-3].x); + dy = (stepsize3*0.5)*ay + (stepsize2*0.5)*by + (stepsize*0.5)*(p[i-1].y-p[i-3].y); + d2x = (stepsize3*3) * ax + stepsize2 * bx; + d2y = (stepsize3*3) * ay + stepsize2 * by; + d3x = (stepsize3*3) * ax; + d3y = (stepsize3*3) * ay; + + /* calculate the points for drawing the curve */ + + for (j = 0; j < steps; j++) { + x = x + dx; + y = y + dy; + dx = dx + d2x; + dy = dy + d2y; + d2x = d2x + d3x; + d2y = d2y + d3y; + thepoints[j + 1].x = (int)x; + thepoints[j + 1].y = (int)y; + } + helper(w, thepoints, steps + 1); + } + if (thepoints != NULL) { + free(thepoints); + thepoints = NULL; + } + } + +static void curveHelper(wbp w, XPoint *thepoints, int n) + { + /* + * Could use drawpoints(w, thepoints, n) + * but that ignores the linewidth and linestyle attributes... + * Might make linestyle work a little better by "compressing" straight + * sections produced by genCurve into single drawline points. + */ + drawlines(w, thepoints, n); + } + +/* + * draw a smooth curve through the array of points + */ +void drawCurve(w, p, n) +wbp w; +XPoint *p; +int n; + { + genCurve(w, p, n, curveHelper); + } + +/* + * Compare two unsigned long values for qsort or qsearch. + */ +int ulcmp(p1, p2) +pointer p1, p2; + { + register unsigned long u1 = *(unsigned int *)p1; + register unsigned long u2 = *(unsigned int *)p2; + + if (u1 < u2) + return -1; + else + return (u1 > u2); + } + +/* + * the next section consists of code to deal with string-integer + * (stringint) symbols. See graphics.h. + */ + +/* + * string-integer comparison, for qsearch() + */ +static int sicmp(sip1,sip2) +siptr sip1, sip2; +{ + return strcmp(sip1->s, sip2->s); +} + +/* + * string-integer lookup function: given a string, return its integer + */ +int si_s2i(sip,s) +siptr sip; +char *s; +{ + stringint key; + siptr p; + key.s = s; + + p = (siptr)qsearch((char *)&key,(char *)(sip+1),sip[0].i,sizeof(key),sicmp); + if (p) return p->i; + return -1; +} + +/* + * string-integer inverse function: given an integer, return its string + */ +char *si_i2s(sip,i) +siptr sip; +int i; +{ + register siptr sip2 = sip+1; + for(;sip2<=sip+sip[0].i;sip2++) if (sip2->i == i) return sip2->s; + return NULL; +} + + +/* + * And now, the stringint data. + * Convention: the 0'th element of a stringint array contains the + * NULL string, and an integer count of the # of elements in the array. + */ + +stringint attribs[] = { + { 0, NUMATTRIBS}, + {"ascent", A_ASCENT}, + {"bg", A_BG}, + {"canvas", A_CANVAS}, + {"ceol", A_CEOL}, + {"cliph", A_CLIPH}, + {"clipw", A_CLIPW}, + {"clipx", A_CLIPX}, + {"clipy", A_CLIPY}, + {"col", A_COL}, + {"columns", A_COLUMNS}, + {"cursor", A_CURSOR}, + {"depth", A_DEPTH}, + {"descent", A_DESCENT}, + {"display", A_DISPLAY}, + {"displayheight", A_DISPLAYHEIGHT}, + {"displaywidth", A_DISPLAYWIDTH}, + {"drawop", A_DRAWOP}, + {"dx", A_DX}, + {"dy", A_DY}, + {"echo", A_ECHO}, + {"fg", A_FG}, + {"fheight", A_FHEIGHT}, + {"fillstyle", A_FILLSTYLE}, + {"font", A_FONT}, + {"fwidth", A_FWIDTH}, + {"gamma", A_GAMMA}, + {"geometry", A_GEOMETRY}, + {"height", A_HEIGHT}, + {"iconic", A_ICONIC}, + {"iconimage", A_ICONIMAGE}, + {"iconlabel", A_ICONLABEL}, + {"iconpos", A_ICONPOS}, + {"image", A_IMAGE}, + {"label", A_LABEL}, + {"leading", A_LEADING}, + {"lines", A_LINES}, + {"linestyle", A_LINESTYLE}, + {"linewidth", A_LINEWIDTH}, + {"pattern", A_PATTERN}, + {"pointer", A_POINTER}, + {"pointercol", A_POINTERCOL}, + {"pointerrow", A_POINTERROW}, + {"pointerx", A_POINTERX}, + {"pointery", A_POINTERY}, + {"pos", A_POS}, + {"posx", A_POSX}, + {"posy", A_POSY}, + {"resize", A_RESIZE}, + {"reverse", A_REVERSE}, + {"row", A_ROW}, + {"rows", A_ROWS}, + {"size", A_SIZE}, + {"visual", A_VISUAL}, + {"width", A_WIDTH}, + {"windowlabel", A_WINDOWLABEL}, + {"x", A_X}, + {"y", A_Y}, +}; + + +/* + * There are more, X-specific stringint arrays in ../common/xwindow.c + */ + +#endif /* Graphics */ |