diff options
Diffstat (limited to 'src/runtime/rxwin.ri')
-rw-r--r-- | src/runtime/rxwin.ri | 3475 |
1 files changed, 3475 insertions, 0 deletions
diff --git a/src/runtime/rxwin.ri b/src/runtime/rxwin.ri new file mode 100644 index 0000000..c2dc48c --- /dev/null +++ b/src/runtime/rxwin.ri @@ -0,0 +1,3475 @@ +/* + * File: rxwin.ri - X11 system-specific graphics interface code. + */ + +#ifdef Graphics + +#define RootState IconicState+1 + +/* + * Global variables specific to X + */ +static XSizeHints size_hints; + +/* + * function prototypes + */ +static int handle_misc (wdp display, wbp w); +static int handle_config (wbp w, XConfigureEvent *event); +static int handle_exposures (wbp w, XExposeEvent *event); +static void handle_mouse (wbp w, XButtonEvent *event); +static void handle_keypress (wbp w, XKeyEvent *event); +static void postcursor (wbp w); +static void scrubcursor (wbp w); +static XImage * getximage (wbp w, int x, int y, + int width, int height, int init); +static void moveWindow (wbp w, int x, int y); +static void makeIcon (wbp w, int x, int y); +static int wmap (wbp w); +static Pixmap loadimage (wbp w, char *filename, unsigned int *height, + unsigned int *width, int atorigin, int *status); + + +/* + * write some text to both the window and the pixmap + */ +void xdis(w,s,n) +register wbp w; +char *s; +int n; + { + int x, y, delta_x; + STDLOCALS(w); + + pollctr>>=1; pollctr++; + x = ws->x; + y = ws->y; + delta_x = XTextWidth(wc->font->fsp,s,n); + RENDER4(XDrawImageString,x,y,s,n); + ws->x += delta_x; + } + + + +/* + * put a character out to a window using the current attributes + */ +int wputc(ci,w) +int ci; +wbp w; + { + int fh, lh, width, height, over; + char c = (char)ci; + STDLOCALS(w); + + fh = wc->font->height; + lh = wc->leading; + width = ws->width; + height = ws->height; + + switch(c) { + case '\r': { + ws->x = wc->dx; + break; + } + case '\n': { + if (ISCEOLON(w)) { + /* + * Clear the rest of the line, like a terminal would. + * Its arguable whether this should clear to the window + * background or the current context background. If you + * change it to use the context background you have to + * change the XClearArea call to another XFillRectangle + * (cf. eraseArea()). + */ + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy); + XSetForeground(stddpy, stdgc, wc->bg->c); + XClearArea(stddpy, stdwin, + ws->x, ws->y-wc->font->fsp->max_bounds.ascent, + width-ws->x, lh, False); + XFillRectangle(stddpy, stdpix, stdgc, + ws->x, ws->y - wc->font->fsp->max_bounds.ascent, + width - ws->x, lh); + XSetForeground(stddpy, stdgc,wc->fg->c^(ISXORREVERSE(w)?wc->bg->c:0)); + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop); + } + ws->y += lh; + ws->x = wc->dx; + /* + * Now for the exciting part: do we scroll the window? + * Copy the pixmap upward, then repaint the window. + */ + over = ws->y + wc->font->fsp->max_bounds.descent - height; + if (over > 0) { + ws->y -= over; + + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy); + XCopyArea(stddpy, stdpix, stdpix, stdgc, + 0, over, /* x, y */ + width, height - over, /* w, h */ + 0, 0); /* dstx,dsty */ + XSetForeground(stddpy, stdgc, wc->bg->c); + XFillRectangle(stddpy, stdpix, stdgc, + 0, height - over, width, over); + XSetForeground(stddpy, stdgc,wc->fg->c^(ISXORREVERSE(w)?wc->bg->c:0)); + if (stdwin) + XCopyArea(stddpy, stdpix, stdwin, stdgc, 0, 0, width, height, 0,0); + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop); + } + break; + } + case '\t': { + xdis(w, " ", 8 - ((XTOCOL(w,ws->x))&7)); + break; + } + /* + * Handle backspaces. This implements cooked mode echo handling. + */ + case '\177': + case '\010': { + int i = 0, pre_x; + /* + * Start with the last character queued up. + */ + i--; + /* + * Trot back to the control-H itself. + */ + while ((i>-EQUEUELEN) && (EVQUESUB(w,i) != c)) i--; + if (i == -EQUEUELEN) break; + /* + * Go past the control-H. + */ + i--; + /* + * Go back through any number of control-H's from prior lifetimes. + */ + while((i > -EQUEUELEN) && !isprint(EVQUESUB(w,i))) i--; + if (i == -EQUEUELEN) break; + + /* + * OK, here's the character we're actually rubbing out. Back up. + */ + c = EVQUESUB(w,i); + pre_x = ws->x; + ws->x -= XTextWidth(wc->font->fsp, &c, 1); + /* + * Physically erase the character from the queue. This results in + * two control-H's present in the queue. + */ + *evquesub(w,i) = '\010'; + /* + * Save the backed-up position, and draw spaces through the erased. + */ + i = ws->x; + while(ws->x < pre_x) xdis(w," ",1); + ws->x = i; + break; + } + default: { + xdis(w,&c,1); + } + } + return 1; + } + + +/* + * handle_misc processes pending events on display. + * if w is non-null, block until a returnable event arrives. + * returns 1 on success, 0 on failure, and -1 on error. + */ +int handle_misc(wd, w) +wdp wd; +wbp w; + { + XEvent event; + Window evwin; + static int presscount = 0; + wbp wb; + wsp ws; + + while ((w != NULL) || XPending(wd->display)) { + + XNextEvent(wd->display, &event); + evwin = event.xexpose.window; /* go ahead, criticize all you like */ + +/* could avoid doing this search every event by handling 1 window at a time */ + for (wb = wbndngs; wb; wb=wb->next) { + ws = wb->window; + + if ((ws->display == wd) && + ((ws->win == evwin) || (ws->iconwin == evwin) || + (ws->pix == evwin) || (ws->initialPix == evwin))) break; + } + if (!wb) continue; + if (evwin == ws->iconwin) { + switch (event.type) { + case Expose: + if (ws->iconpix) + XCopyArea(wd->display, ws->iconpix, ws->iconwin, + wd->icongc, 0, 0, ws->iconw, ws->iconh, 3, 3); + else + XDrawString(wd->display, evwin, wd->icongc, 4, + ws->display->fonts->fsp->max_bounds.ascent + 2, + ws->iconlabel, strlen(ws->iconlabel)); + if (ws->iconic == IconicState) + SETEXPOSED(wb); + break; + case KeyPress: + handle_keypress(wb, (XKeyEvent *)&event); + break; + case ButtonPress: + if (ws->iconic == IconicState) + XMapWindow(ws->display->display, ws->win); + ws->iconic = NormalState; /* set the current state */ + break; + case ConfigureNotify: + ws->iconx = ((XConfigureEvent *)&event)->x; + ws->icony = ((XConfigureEvent *)&event)->y; + break; + } + } + else { + switch (event.type) { + case KeyPress: + handle_keypress(wb, (XKeyEvent *)&event); + break; + case ButtonPress: + presscount++; + handle_mouse(wb, (XButtonEvent *)&event); + break; + case ButtonRelease: + if (--presscount < 0) presscount = 0; + handle_mouse(wb, (XButtonEvent *)&event); + break; + case MotionNotify: + if (presscount) + handle_mouse(wb, (XButtonEvent *)&event); + break; + case NoExpose: + break; + case Expose: + if (!handle_exposures(wb, (XExposeEvent *)&event)) + return 1; + continue; + case UnmapNotify: + wb->window->iconic = IconicState; + continue; + case MapNotify: + if ((ws->width != DisplayWidth(wd->display, wd->screen)) || + (ws->height != DisplayHeight(wd->display, wd->screen))) + ws->iconic = NormalState; + else + ws->iconic = MaximizedState; + continue; + case ConfigureNotify: + if (!handle_config(wb, (XConfigureEvent *)&event)) { + return 0; + } + break; + case DestroyNotify: + if (!ISZOMBIE(wb)) return -1; /* error #141 */ + + /* + * first of all, we are done with this window + */ + ws->win = (Window) NULL; + + /* + * if there are no more references, we are done with the pixmap + * too. Free it and the colors allocated for this canvas. + */ + if (ws->refcount == 0) { + if (wb->window->pix) { + Display *d = ws->display->display; + XSync(d, False); + if (ws->pix) + XFreePixmap(d, ws->pix); + ws->pix = (Pixmap) NULL; + } + if (ws->initialPix != (Pixmap) NULL) { + Display *d = ws->display->display; + XSync(d, False); + XFreePixmap(d, ws->initialPix); + ws->initialPix = (Pixmap) NULL; + } + free_xcolors(wb, 2); /* free regular colors */ + free_xcolors(wb, 1); /* free icon colors */ + } + break; + default: + continue; + } + if ((w != NULL) && + ((evwin == w->window->win) || (evwin == w->window->iconwin))) { + return 1; + } + } + } + return 1; + } + +/* + * poll for available events on all opened displays. + * this is where the interpreter calls into the X interface. + */ +int pollevent() + { + wdp wd; + int hm; + for (wd = wdsplys; wd; wd = wd->next) { + if ((hm = handle_misc(wd, NULL)) < 1) { + if (hm == -1) return -1; + else if (hm == 0) { + /* how to handle failure? */ + } + } + } + return 400; + } + +/* + * get a single item from w's pending queue + */ +int wgetq(w,res) +wbp w; +dptr res; + { + int posted = 0; + + while (1) { + STDLOCALS(w); /* leave inside loop; ws->pix can change! */ + if (!EVQUEEMPTY(w)) { + EVQUEGET(w,*res); + if (posted) + scrubcursor(w); + return 1; + } + postcursor(w); /* post every time in case resize erased it */ + posted = 1; + if (handle_misc(wd, w) == -1) { + if (posted) + scrubcursor(w); + return -1; + } + } + } + +/* + * postcursor/scrubcursor calls must be paired without any intervening output. + */ +static void postcursor(w) +wbp w; + { + STDLOCALS(w); + + if (!ISCURSORON(w) || !stdwin) return; + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy); + if (ISXORREVERSE(w)) XSetForeground(stddpy, stdgc, wc->fg->c); + + /* Draw only on window, not on backing pixmap */ + XFillRectangle(stddpy, stdwin, stdgc, ws->x, ws->y, FWIDTH(w), DESCENT(w)); + XSync(stddpy, False); + } + +static void scrubcursor(w) +wbp w; + { + STDLOCALS(w); + + if (!ISCURSORON(w) || !stdwin) return; + + XCopyArea(stddpy, stdpix, stdwin, stdgc, /* restore window from pixmap */ + ws->x, ws->y, FWIDTH(w), DESCENT(w), ws->x, ws->y); + + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop); + if (ISXORREVERSE(w)) XSetForeground(stddpy, stdgc, wc->fg->c ^ wc->bg->c); + } + +/* + * wclose - close a window. If is a real on-screen window, + * wait for a DestroyNotify event from the server before returning. + */ +int wclose(w) +wbp w; + { + STDLOCALS(w); + + XSync(stddpy, False); + if (pollevent() == -1) return -1; + + /* + * Force window to close (turn into a pixmap) + */ + if (ws->win && ws->refcount > 1) { + SETZOMBIE(w); + XDestroyWindow(stddpy,stdwin); + XFlush(stddpy); + ws->refcount--; + while (ws->win) + if (pollevent() == -1) return -1; + } + /* + * Entire canvas terminates + */ + else { + free_xcolors(w, 2); + free_xcolors(w, 1); + free_window(ws); + } + + return 0; + } +/* + * flush a window + */ +void wflush(w) +wbp w; + { + STDLOCALS(w); + XFlush(stddpy); + } +/* + * flush all windows + */ +void wflushall() + { + wdp wd; + for (wd = wdsplys; wd != NULL; wd = wd->next) { + XFlush(wd->display); + } + } +/* + * sync all the servers + */ +void wsync(w) +wbp w; + { + wdp wd; + if (w == NULL) { + for (wd = wdsplys; wd != NULL; wd = wd->next) { + XSync(wd->display, False); + } + } + else + XSync(w->window->display->display, False); + } + +/* + * open a window + * This routine really just allocates a window data structure. + * The interesting part is done in wmap, after the user preferences + * passed to Icon have been parsed. Returns NULL on error/failure; + * err_index is set to one of: + * >= 0: the index of an offending attribute value + * -1 : ordinary failure + * -2 : out of memory + */ +FILE *wopen(name, lp, attr, n, err_index) +char *name; +struct b_list *lp; +dptr attr; +int n, *err_index; + { + wbp w; + wsp ws; + char dispchrs[256]; + char answer[128]; + char *display = NULL; + int i; + tended struct b_list *tlp; + tended struct descrip attrrslt; + + tlp = lp; + + for(i=0;i<n;i++) { + if (is:string(attr[i]) && + (StrLen(attr[i])>8) && + !strncmp("display=",StrLoc(attr[i]),8)) { + strncpy(dispchrs,StrLoc(attr[i])+8,StrLen(attr[i])-8); + dispchrs[StrLen(attr[i]) - 8] = '\0'; + display = dispchrs; + } + } + + if ((w = alc_wbinding()) == NULL) { + *err_index = -2; + return NULL; + } + if ((w->window = alc_winstate()) == NULL) { + *err_index = -2; + free_binding(w); + return NULL; + } + if ((w->window->display = alc_display(display)) == NULL) { + *err_index = -1; /* might be out of memory, probably bad DISPLAY var. */ + free_binding(w); + return NULL; + } + ws = w->window; + ws->listp.dword = D_List; + BlkLoc(ws->listp) = (union block *)tlp; + + /* + * some attributes of the display and window are used in the context + */ + if ((w->context = alc_context(w)) == NULL) { + *err_index = -2; + free_binding(w); + return NULL; + } + + /* + * some attributes of the context determine window defaults + */ + ws->height = w->context->font->height * 12; + ws->width = w->context->font->fsp->max_bounds.width * 80; + ws->y = w->context->font->fsp->max_bounds.ascent; + ws->x = 0; + ws->y += w->context->dy; + ws->x += w->context->dx; + + /* + * Loop through any remaining arguments. + */ + for (i = 0; i < n; i++){ + /* + * write the attribute, + * except "display=" attribute, which is done earlier + */ + if((StrLen(attr[i])<9)||strncmp(StrLoc(attr[i]),"display=",8)) { + switch (wattrib((wbp) w, StrLoc(attr[i]), StrLen(attr[i]), &attrrslt, + answer)) { + case Error: + *err_index = i; + return NULL; + case Failed: + free_binding((wbp)w); + *err_index = -1; + return NULL; + } + } + } + if (ws->windowlabel == NULL) { + ws->windowlabel = salloc(name); + if (ws->windowlabel == NULL) { /* out of memory */ + *err_index = -2; + return NULL; + } + } + + if ((i = wmap(w)) != Succeeded) { + if (i == Failed) *err_index = -1; + else *err_index = 0; + return NULL; + } + return (FILE *)w; + } + +/* + * make an icon for a window + */ +void makeIcon(w, x, y) +wbp w; +int x, y; /* current mouse position */ +{ + int status; + STDLOCALS(w); + + /* if a pixmap image has been specified, load it */ + if (ws->initicon.width) { + ws->iconpix = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), + ws->iconw, ws->iconh, + DefaultDepth(stddpy,wd->screen)); + } + else if (ws->iconimage && strcmp(ws->iconimage, "")) { + ws->iconpix = loadimage(w, ws->iconimage, &(ws->iconh), &(ws->iconw), + 0, &status); + ws->iconh += 6; + ws->iconw += 6; + } + else { /* determine the size of the icon window */ + ws->iconh = wd->fonts->fsp->max_bounds.ascent + + wd->fonts->fsp->max_bounds.descent + 5; + if (ws->iconlabel == NULL) ws->iconlabel = ""; + ws->iconw = XTextWidth(wd->fonts->fsp, ws->iconlabel, + strlen(ws->iconlabel)) + 6; + } + + /* if icon position hint exists, get it */ + if (ws->wmhintflags & IconPositionHint) { + x = ws->iconx; + y = ws->icony; + } + + /* create the icon window */ + ws->iconwin = XCreateSimpleWindow(stddpy, DefaultRootWindow(stddpy), x, y, + ws->iconw, ws->iconh, 2, wc->fg->c, + wc->bg->c); + + /* select events for the icon window */ + XSelectInput(stddpy, ws->iconwin, + ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask); + +} + +/* + * Create a canvas. + * If a window, cause the window to actually become visible on the screen. + * returns Succeeded, Failed, or Error + */ +int wmap(w) +wbp w; + { + XWindowAttributes attrs; + XGCValues gcv; + unsigned long gcmask = + GCFont | GCForeground | GCBackground | GCFillStyle | GCCapStyle; + struct imgdata *imd; + int i, r; + int new_pixmap = 0; + char *p, *s; + XWMHints wmhints; + XClassHint clhints; + STDLOCALS(w); + + /* + * Create a pixmap for this canvas if there isn't one already. + */ + if (ws->pix == (Pixmap) NULL) { + if (ws->initialPix) { + ws->pix = ws->initialPix; + ws->initialPix = (Pixmap) NULL; + ws->pixwidth = ws->width; + ws->pixheight = ws->height; + } + else { + ws->pix = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), + ws->width, ws->height, + DefaultDepth(stddpy,wd->screen)); + ws->pixwidth = ws->width; + ws->pixheight = ws->height; + new_pixmap = 1; + } + stdpix = ws->pix; + } + + /* + * create the X window (or use the DefaultRootWindow if requested) + */ + if (ws->iconic != HiddenState) { + ws->win = ((ws->iconic == RootState) ? DefaultRootWindow(stddpy) : + XCreateSimpleWindow(stddpy, DefaultRootWindow(stddpy), + ws->posx < 0 ? 0 : ws->posx, + ws->posy < 0 ? 0 : ws->posy, ws->width, + ws->height, 1, wc->fg->c, wc->bg->c)); + if (ws->win == (Window) NULL) + return Failed; + stdwin = ws->win; + XClearWindow(stddpy, stdwin); + } + + /* + * before creating the graphics context, construct a description + * of any non-default initial graphics context values. + */ + gcv.foreground = wc->fg->c ^ (ISXORREVERSE(w) ? wc->bg->c : 0); + gcv.background = wc->bg->c; + gcv.font = wc->font->fsp->fid; + if (wc->fillstyle) + gcv.fill_style = wc->fillstyle; + else + gcv.fill_style = wc->fillstyle = FillSolid; + if (wc->linestyle || wc->linewidth) { + gcmask |= (GCLineWidth | GCLineStyle); + gcv.line_width = wc->linewidth; + gcv.line_style = wc->linestyle; + if (wc->linewidth > 1) { + gcv.dashes = 3 * wc->linewidth; + gcmask |= GCDashList; + } + } + else + wc->linestyle = LineSolid; + gcv.cap_style = CapProjecting; + + /* + * Create a graphics context (or change an existing one to conform + * with initial values). + */ + if (stdgc == NULL) { + wc->gc = XCreateGC(stddpy, stdpix, gcmask, &gcv); + stdgc = wc->gc; + if (stdgc == NULL) return Failed; + } + else + XChangeGC(stddpy, stdgc, gcmask, &gcv); + + if (wc->clipw >= 0) + setclip(w); + + if (new_pixmap) { + XSetForeground(stddpy, stdgc, wc->bg->c); + XFillRectangle(stddpy, ws->pix, stdgc, 0, 0, ws->width, ws->height); + XSetForeground(stddpy, stdgc, wc->fg->c ^(ISXORREVERSE(w)?wc->bg->c:0)); + } + + imd = &ws->initimage; + if (imd->width) { + r = strimage(w, 0, 0, imd->width, imd->height, imd->paltbl, + imd->data, (word)imd->width * (word)imd->height, 0); + free((pointer)imd->paltbl); + free((pointer)imd->data); + imd->width = 0; + if (r < 0) + return Failed; + } + + imd = &ws->initicon; + if (imd->width) { + r = strimage(w, 0, 0, imd->width, imd->height, imd->paltbl, + imd->data, (word)imd->width * (word)imd->height, 1); + free((pointer)imd->paltbl); + free((pointer)imd->data); + imd->width = 0; + if (r < 0) + return Failed; + wmhints.icon_window = ws->iconwin; + ws->wmhintflags |= IconWindowHint; + } + + if (wc->patternname != NULL) { + if (SetPattern(w, wc->patternname, strlen(wc->patternname)) != Succeeded) + return Failed; + } + + /* + * if we are opening a pixmap, we are done at this point. + */ + if (stdwin == (Window) NULL) return Succeeded; + + if (ws->iconic != RootState) { + size_hints.flags = PSize | PMinSize | PMaxSize; + size_hints.width = ws->width; + size_hints.height= ws->height; + if (ws->posx == -(MaxInt)) ws->posx = 0; + else size_hints.flags |= USPosition; + if (ws->posy == -(MaxInt)) ws->posy = 0; + else size_hints.flags |= USPosition; + size_hints.x = ws->posx; + size_hints.y = ws->posy; + if (ISRESIZABLE(w)) { + size_hints.min_width = 0; + size_hints.min_height = 0; + size_hints.max_width = DisplayWidth(stddpy, wd->screen); + size_hints.max_height = DisplayHeight(stddpy, wd->screen); + } + else { + size_hints.min_width = size_hints.max_width = ws->width; + size_hints.min_height = size_hints.max_height = ws->height; + } + if (ws->iconlabel == NULL) { + if ((ws->iconlabel = salloc(ws->windowlabel)) == NULL) + ReturnErrNum(305, Error); + } + XSetStandardProperties(stddpy, stdwin, ws->windowlabel, ws->iconlabel, + 0,0,0, &size_hints); + XSelectInput(stddpy, stdwin, ExposureMask | KeyPressMask | + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + StructureNotifyMask); + } + + wmhints.input = True; + wmhints.flags = InputHint; + if (ws->iconic != RootState) { + if (ws->iconimage != NULL) { + makeIcon(w, ws->posx < 0 ? 0 : ws->posx, ws->posy < 0 ? 0 : ws->posy); + wmhints.icon_window = ws->iconwin; + ws->wmhintflags |= IconWindowHint; + } + wmhints.flags |= (ws->wmhintflags | StateHint); + wmhints.initial_state = ws->iconic; + wmhints.icon_x = ws->iconx; + wmhints.icon_y = ws->icony; + } + XSetWMHints(stddpy, stdwin, &wmhints); + + /* + * Set the class hints that name the program (for reference by the + * window manager) following conventions given in O'Reilly. + */ + if (! (s = getenv("RESOURCE_NAME"))) { + p = StrLoc(kywd_prog); + s = p + StrLen(kywd_prog); + while (s > p && s[-1] != '/') + s--; /* find tail of prog_name */ + } + clhints.res_name = s; + clhints.res_class = "IconProg"; + XSetClassHint(stddpy, stdwin, &clhints); + + if (wd->cmap != DefaultColormap(stddpy,wd->screen)) + XSetWindowColormap(stddpy, stdwin, wd->cmap); + + if (ws->iconic != RootState) { + CLREXPOSED(w); + XMapWindow(stddpy, stdwin); + } + + XGetWindowAttributes(stddpy, stdwin, &attrs); + ws->width = attrs.width; + ws->height = attrs.height; + if (!resizePixmap(w, ws->width, ws->height)) return Failed; + + if (stdwin) { + i = ws->theCursor; + if (!(wd->cursors[i])) + wd->cursors[i] = XCreateFontCursor(stddpy, 2 * i); + XDefineCursor(stddpy, stdwin, wd->cursors[i]); + } + + /* + * busy loop for an expose event, unless of course we are starting out + * in an iconic state + */ + CLRZOMBIE(w); + if (ws->win != (Window) NULL) { + int hm; + while (!ISEXPOSED(w) && (ws->iconic != IconicState || ws->iconwin)) { + if ((hm = handle_misc(wd, w)) < 1) { + if (hm == -1) return Error; + else if (hm == 0) { + /* how to handle failure? */ + } + } + } + } + + XSetFunction(stddpy, stdgc, wc->drawop); + XSync(stddpy, False); + return Succeeded; +} + + +int do_config(w, status) +wbp w; +int status; + { + wsp ws = w->window; + wdp wd = ws->display; + int wid = ws->width, ht = ws->height; + int posx = ws->posx, posy = ws->posy; + XTextProperty textprop; + + if (! resizePixmap(w, ws->width, ws->height)) + return Failed; + if (ws->win) { + XSync(wd->display, False); + pollevent(); + if (status == 1) + moveWindow(w, posx, posy); + else { + if (status == 2) + posx = posy = -MaxInt; + if (moveResizeWindow(w, posx, posy, wid, ht) == Failed) + return Failed; + } + + /* XSync is not enough because the window manager gets involved here. */ + XFlush(wd->display); /* force out request */ + XGetWMName(wd->display, ws->win, &textprop); /* force WM round trip */ + XSync(wd->display, False); /* NOW sync */ + } + return Succeeded; + } + +int setheight(w, new_height) +wbp w; +SHORT new_height; + { + STDLOCALS(w); + if (new_height < 0) return Failed; + ws->height = size_hints.height = new_height; + return Succeeded; + } + +int setwidth(w, new_width) +wbp w; +SHORT new_width; +{ + STDLOCALS(w); + if (new_width < 0) return Failed; + ws->width = size_hints.width = new_width; + return Succeeded; +} + +int setgeometry(w, geo) +wbp w; +char *geo; + { + int width = 0, height = 0; + int x = 0, y = 0, status; + STDLOCALS(w); + + if ((status = parsegeometry(geo, &x, &y, &width, &height)) == 0) + return Error; + if (status & 1) { + ws->width = size_hints.width = width; + ws->height = size_hints.height = height; + } + /* + * can't set position on hidden windows + */ + if ((stdwin || !stdpix) && (status & 2)) { + ws->posx = x; + ws->posy = y; + } + /* insert assigns here: + * ws->posx = ((sign > 0) ? tmp : + * DisplayWidth(stddpy,wd->screen) - ws->width - tmp); + * ws->posy = ((sign > 0) ? tmp : + * DisplayHeight(stddpy,wd->screen) - ws->height - tmp); + */ + return Succeeded; + } + +int allowresize(w, on) +wbp w; +int on; + { + if (on) + SETRESIZABLE(w); + else + CLRRESIZABLE(w); + return Succeeded; + } + +void warpPointer(w, x, y) +wbp w; +int x, y; + { + wsp ws = w->window; + XWarpPointer(ws->display->display, None, ws->win, 0,0,0,0, x, y); + } + +/* + * #@#@ This is a bug + */ +int seticonlabel(w, val) +wbp w; +char *val; + { + STDLOCALS(w); + if (ws->iconlabel != NULL) free(ws->iconlabel); + if ((ws->iconlabel = salloc(val)) == NULL) + ReturnErrNum(305, Error); + + if (stddpy && stdwin) { + XSetIconName(stddpy, stdwin, w->window->iconlabel); + if (ws->iconic == IconicState && !ws->iconpix && ws->iconwin) { + XClearWindow(stddpy, ws->iconwin); + XDrawString(stddpy, ws->iconwin, wd->icongc, 4, + wd->fonts->fsp->max_bounds.ascent + 2, + ws->iconlabel, strlen(ws->iconlabel)); + } + } + return Succeeded; + } + +/* + * setwindowlabel + */ +int setwindowlabel(w, s) +wbp w; +char *s; +{ + wsp ws = w->window; + if (ws->windowlabel != NULL) free(ws->windowlabel); + if ((ws->windowlabel = salloc(s)) == NULL) + ReturnErrNum(305, Error); + if (ws->display && ws->display->display && ws->win) + XStoreName(ws->display->display, ws->win, + *ws->windowlabel ? ws->windowlabel : " "); /* empty string fails */ + return Succeeded; +} + +/* + * setcursor() - a no-op under X at present + */ +int setcursor(w, on) +wbp w; +int on; +{ + if (on) + SETCURSORON(w); + else + CLRCURSORON(w); + return Succeeded; +} + + +/* + * setpointer() - define a mouse pointer shape + */ +int setpointer(w, val) +wbp w; +char *val; + { + int i = si_s2i(cursorsyms,val) >> 1; + STDLOCALS(w); + if (i < 0 || i >= NUMCURSORSYMS) return Failed; + + ws->theCursor = i; + if (!(wd->cursors[i])) + wd->cursors[i] = XCreateFontCursor(stddpy, 2 * i); + if (stdwin) + XDefineCursor(stddpy, stdwin, wd->cursors[i]); + return Succeeded; + } + +/* + * setdrawop() - set the drawing operation + */ +int setdrawop(w, val) +wbp w; +char *val; + { + STDLOCALS(w); + XSync(stddpy, False); + if (!strcmp(val,"reverse")) { + if (!ISXORREVERSE(w)) { + SETXORREVERSE(w); + wc->drawop = GXxor; + if (stdgc) + XSetForeground(stddpy, stdgc, wc->fg->c ^ wc->bg->c); + } + } + else { + if (ISXORREVERSE(w)) { + CLRXORREVERSE(w); + if (stdgc) + XSetForeground(stddpy, stdgc, wc->fg->c); + } + wc->drawop = si_s2i(drawops,val); + if (wc->drawop == -1) { wc->drawop = GXcopy; return Error; } + } + if (stdgc) XSetFunction(stddpy, stdgc, wc->drawop); + return Succeeded; + } + +/* + * rebind() - bind w's context to that of w2. + */ +int rebind(w, w2) +wbp w, w2; + { + if (w->window->display != w2->context->display) return Failed; + w->context = w2->context; + return Succeeded; + } + + +void setclip(w) +wbp w; + { + wcp wc = w->context; + XRectangle rec; + if (wc->gc) { + rec.x = wc->clipx; + rec.y = wc->clipy; + rec.width = wc->clipw; + rec.height = wc->cliph; + XSetClipRectangles(wc->display->display, wc->gc, 0, 0, &rec, 1,Unsorted); + } + } + +void unsetclip(w) +wbp w; + { + wcp wc = w->context; + if (wc->gc) { + XSetClipMask(wc->display->display, wc->gc, None); + } + } + +void getcanvas(w, s) +wbp w; +char *s; + { + if (w->window->win == (Window) NULL) sprintf(s, "hidden"); + else + switch (w->window->iconic) { + case RootState: + sprintf(s, "root"); + break; + case NormalState: + sprintf(s, "normal"); + break; + case IconicState: + sprintf(s, "iconic"); + break; + case MaximizedState: + sprintf(s, "maximal"); + break; + case HiddenState: + sprintf(s, "hidden"); + break; + default: + sprintf(s, "???"); + } + } + +/* + * Set the canvas type, either during open (pixmap is null, set a flag) + * or change an existing canvas to a different type. + */ +int setcanvas(w,s) +wbp w; +char *s; + { + int hm; + XTextProperty textprop; + STDLOCALS(w); + + if (!strcmp(s, "iconic")) { + if (ws->pix == (Pixmap) NULL) { + ws->wmhintflags |= StateHint; + ws->iconic = IconicState; + } + else { + if (ws->iconic != IconicState) { +#ifdef Iconify + if (ws->win == (Window) NULL) { + wmap(w); + } + XIconifyWindow(ws->display->display, ws->win, ws->display->screen); + XSync(stddpy, False); + while (ws->iconic != IconicState) + if ((hm = handle_misc(wd, NULL)) < 1) { + if (hm == -1) return Error; + else if (hm == 0) { + return Failed; + } + } +#else /* Iconify */ + return Failed; +#endif /* Iconify */ + } + } + } + + else if (!strcmp(s, "normal")) { + if (ws->pix == (Pixmap) NULL) { + ws->iconic = NormalState; + } + else { + if (ws->win == (Window) NULL) { + ws->iconic = NormalState; + ws->initialPix = ws->pix; + ws->pix = (Window) NULL; + wmap(w); + } + else if (ws->iconic == IconicState) { + XMapWindow(stddpy, stdwin); + XSync(stddpy, False); + while (ws->iconic == IconicState) + pollevent(); + } + else if (ws->iconic == MaximizedState) { + moveResizeWindow(w, ws->normalx, ws->normaly, + ws->normalw, ws->normalh); + ws->iconic = NormalState; + } + } + } + else if (!strcmp(s, "maximal")) { + if (ws->iconic != MaximizedState) { + int expect_config= (ws->width != DisplayWidth(stddpy, wd->screen)) || + (ws->height != DisplayHeight(stddpy, wd->screen)); + ws->normalx = ws->posx; + ws->normaly = ws->posy; + ws->normalw = ws->width; + ws->normalh = ws->height; + ws->width = DisplayWidth(stddpy, wd->screen); + ws->height= DisplayHeight(stddpy, wd->screen); + if (ws->pix != (Pixmap) NULL) { + if (ws->win == (Window) NULL) { + ws->iconic = MaximizedState; + ws->initialPix = ws->pix; + ws->pix = (Window) NULL; + wmap(w); + } + else if (ws->iconic == IconicState) { + XMapWindow(stddpy, stdwin); + XSync(stddpy, False); + while (ws->iconic == IconicState) + pollevent(); + } + else if (expect_config) { + moveResizeWindow(w, 0, 0, ws->width, ws->height); + /* XSync is not enough because window manager gets involved. */ + XFlush(wd->display); /* flush req */ + XGetWMName(wd->display, ws->win, &textprop); /* force WM RT */ + XSync(wd->display, False); /* NOW sync */ + if (pollevent() == -1) return Error; + moveWindow(w, -ws->posx, -ws->posy); + XFlush(wd->display); /* flush req */ + XGetWMName(wd->display, ws->win, &textprop); /* force WM RT */ + XSync(wd->display, False); /* NOW sync */ + } + } + ws->iconic = MaximizedState; + } + } + else if (!strcmp(s, "hidden")) { + if (ws->pix == (Pixmap)NULL) { + ws->iconic = HiddenState; + } + else { + if (ws->win != (Window) NULL) { + if (ws->iconic == MaximizedState) { + ws->posx = ws->normalx; + ws->posy = ws->normaly; + ws->width = ws->normalw; + ws->height = ws->normalh; + ws->iconic = NormalState; + } + if (ws->iconic != IconicState) { + SETZOMBIE(w); + XDestroyWindow(stddpy, stdwin); + XFlush(stddpy); + while (ws->win) + if (pollevent() == -1) + return Error; + } + } + } + } + else return Error; + XSync(ws->display->display, False); + return Succeeded; + } + +int seticonicstate(w,s) +wbp w; +char *s; + { + STDLOCALS(w); + + if (!strcmp(s, "icon")) { + if (ws->pix == (Pixmap) NULL) { + ws->wmhintflags |= StateHint; + ws->iconic = IconicState; + } + else { + if (ws->iconic != IconicState) { +#ifdef Iconify + XIconifyWindow(ws->display->display, ws->win, ws->display->screen); +#else /* Iconify */ + return Failed; +#endif /* Iconify */ + } + } + } + else if (!strcmp(s, "window")) { + if (ws->win != (Window) NULL) { + if (ws->iconic == IconicState) { + XMapWindow(stddpy, stdwin); + } + } + } + else if (!strcmp(s, "root")) { + if (ws->win == (Window) NULL) + ws->iconic = RootState; + else return Failed; + } + else return Error; + XSync(ws->display->display, False); + return Succeeded; + } + +int seticonpos(w,s) +wbp w; +char *s; + { + char *s2; + wsp ws = w->window; + + ws->wmhintflags |= IconPositionHint; + s2 = s; + ws->iconx = atol(s2); + while (isspace(*s2)) s2++; + while (isdigit(*s2)) s2++; + if (*s2++ != ',') return Error; + ws->icony = atol(s2); + + if (ws->win) { + if (ws->iconwin == (Window) NULL) + makeIcon(w, ws->iconx, ws->icony); + if (remap(w, ws->iconx, ws->icony) == -1) return Error; + } + return Succeeded; + } + +int geticonpos(w, s) +wbp w; +char *s; + { + wsp ws = w->window; + sprintf(s,"%d,%d", ws->iconx, ws->icony); + return Succeeded; + } + + +/* + * if the window exists and is visible, set its position to (x,y) + */ +void moveWindow(w,x,y) +wbp w; +int x, y; +{ + STDLOCALS(w); + ws->posx = x; + ws->posy = y; + if (stdwin) { + XMoveWindow(stddpy, stdwin, ws->posx, ws->posy); + XSync(stddpy, False); + } +} + +int moveResizeWindow(w, x, y, width, height) +wbp w; +int x, y, width, height; + { + wsp ws = w->window; + wdp wd = ws->display; + ws->width = width; + ws->height = height; + + size_hints.flags = PMinSize | PMaxSize; + if (ISRESIZABLE(w)) { + size_hints.min_width = 0; + size_hints.min_height = 0; + size_hints.max_width = DisplayWidth(wd->display, wd->screen); + size_hints.max_height = DisplayHeight(wd->display, wd->screen); + } + else { + size_hints.min_width = size_hints.max_width = width; + size_hints.min_height = size_hints.max_height = height; + } + XSetNormalHints(wd->display, ws->win, &size_hints); + + if (resizePixmap(w, width, height) == 0) return Failed; + + if (ws->win != (Window) NULL) { + if (x == -MaxInt && y == -MaxInt) + XResizeWindow(wd->display, ws->win, width, height); + else + XMoveResizeWindow(wd->display, ws->win, x, y, width, height); + XSync(wd->display, False); + } + return Succeeded; + } + +/* + * Set the context's fill style by name. + */ +int setfillstyle(w, s) +wbp w; +char *s; + { + STDLOCALS(w); + + if (!strcmp(s, "solid")) { + wc->fillstyle = FillSolid; + } + else if (!strcmp(s, "masked") + || !strcmp(s, "stippled") || !strcmp(s, "patterned")) { + wc->fillstyle = FillStippled; + } + else if (!strcmp(s, "textured") + || !strcmp(s, "opaquestippled") || !strcmp(s, "opaquepatterned")) { + wc->fillstyle = FillOpaqueStippled; + } + else return Error; + if (stdpix) { + XSetFillStyle(stddpy, stdgc, wc->fillstyle); + } + return Succeeded; + } + +/* + * Set the context's line style by name. + */ +int setlinestyle(w, s) +wbp w; +char *s; + { + STDLOCALS(w); + + if (!strcmp(s, "solid")) { + wc->linestyle = LineSolid; + } + else if (!strcmp(s, "onoff") || !strcmp(s, "dashed")) { + wc->linestyle = LineOnOffDash; + } + else if (!strcmp(s, "doubledash") || !strcmp(s, "striped")) { + wc->linestyle = LineDoubleDash; + } + else return Error; + if (stdpix) { + XSetLineAttributes(stddpy, stdgc, + wc->linewidth, wc->linestyle, CapProjecting, JoinMiter); + } + return Succeeded; + } + +/* + * Set the context's line width + */ +int setlinewidth(w, linewid) +wbp w; +LONG linewid; + { + unsigned long gcmask; + XGCValues gcv; + STDLOCALS(w); + + if (linewid < 0) return Error; + wc->linewidth = linewid; + if (stdpix) { + gcv.line_width = linewid; + gcv.line_style = wc->linestyle; + if (linewid > 1) + gcv.dashes = 3 * wc->linewidth; + else + gcv.dashes = 4; + gcmask = GCLineWidth | GCLineStyle | GCDashList; + XChangeGC(stddpy, stdgc, gcmask, &gcv); + } + + return Succeeded; + } + +/* + * Reset the context's foreground color to whatever it is supposed to be. + */ +int resetfg(w) +wbp w; + { + wcp wc = w->context; + if (wc->gc != NULL) + XSetForeground(wc->display->display, wc->gc, + wc->fg->c ^ (ISXORREVERSE(w) ? wc->bg->c : 0)); + return Succeeded; + } + +/* + * Set the context's foreground color by name. + */ +int setfg(w,s) +wbp w; +char *s; + { + wclrp cp; + STDLOCALS(w); + + Protect(cp = alc_color(w,s), return Failed); + wc->fg = cp; + return resetfg(w); + } + +int setfgrgb(w, r, g, b) +wbp w; +int r, g, b; +{ + char sbuf1[MaxCvtLen]; + sprintf(sbuf1, "%d,%d,%d", r, g, b); + return setfg(w, sbuf1); +} + +/* + * Set the context's foreground color by color cell. + */ +int isetfg(w,fg) +wbp w; +int fg; + { + int i, r, g, b; + STDLOCALS(w); + + if (fg >= 0) { + b = fg & 255; + fg >>= 8; + g = fg & 255; + fg >>= 8; + r = fg & 255; + return setfgrgb(w, r * 257, g * 257, b * 257); + } + for (i = 2; i < wd->numColors; i++) + if (wd->colrptrs[i]->type == MUTABLE && wd->colrptrs[i]->c == -fg - 1) + break; + if (i == wd->numColors) return Failed; + wc->fg = wd->colrptrs[i]; + return resetfg(w); + } + +/* + * Set the window context's background color by name. + */ +int setbg(w,s) +wbp w; +char *s; + { + wclrp cp; + STDLOCALS(w); + + Protect(cp = alc_color(w,s), return Failed); + wc->bg = cp; + + if (stdgc != NULL) + XSetBackground(stddpy, stdgc, wc->bg->c); + return ISXORREVERSE(w) ? resetfg(w) : Succeeded; + } + +int setbgrgb(w, r, g, b) +wbp w; +int r, g, b; +{ + char sbuf1[MaxCvtLen]; + sprintf(sbuf1, "%d,%d,%d", r, g, b); + return setbg(w, sbuf1); +} + +/* + * Set the context's background color by color cell. + */ +int isetbg(w,bg) +wbp w; +int bg; + { + int i, r, g, b; + STDLOCALS(w); + + if (bg >= 0) { + b = bg & 255; + bg >>= 8; + g = bg & 255; + bg >>= 8; + r = bg & 255; + return setbgrgb(w, r * 257, g * 257, b * 257); + } + for (i = 2; i < wd->numColors; i++) + if (wd->colrptrs[i]->type == MUTABLE && wd->colrptrs[i]->c == -bg - 1) + break; + if (i == wd->numColors) return Failed; + wc->bg = wd->colrptrs[i]; + if (stdgc != NULL) + XSetBackground(stddpy, stdgc, wc->bg->c); + return ISXORREVERSE(w) ? resetfg(w) : Succeeded; + } + +/* + * Set the gamma correction value. + */ +int setgamma(w, gamma) +wbp w; +double gamma; + { + w->context->gamma = gamma; + setfg(w, w->context->fg->name); /* reinterpret current Fg/Bg spec */ + setbg(w, w->context->bg->name); + return Succeeded; + } + +/* + * Set the display by name. Really should cache answers as per fonts below; + * for now just open a new display each time. Note that this can only be + * called before a window is instantiated... + */ +int setdisplay(w,s) +wbp w; +char *s; + { + wdp d; + /* can't change display for mapped window! */ + if (w->window->pix != (Pixmap) NULL) + return Failed; + + Protect(d = alc_display(s), return 0); + w->window->display = d; + w->context->fg = d->colrptrs[0]; + w->context->bg = d->colrptrs[1]; + w->context->font = d->fonts; + return Succeeded; + } + +int setleading(w, i) +wbp w; +int i; +{ + w->context->leading = i; + return Succeeded; +} + +int setimage(w, val) +wbp w; +char *val; + { + wsp ws = w->window; + int status; + ws->initialPix = loadimage(w, val, &(ws->height), &(ws->width), + 0, &status); + if (ws->initialPix == (Pixmap) NULL) return Failed; + return Succeeded; + } + +void toggle_fgbg(w) +wbp w; +{ + wclrp tmp; + STDLOCALS(w); + tmp = wc->fg; + wc->fg = wc->bg; + wc->bg = tmp; + if (stdpix) { + XSetForeground(stddpy, stdgc, + wc->fg->c ^ (ISXORREVERSE(w)?wc->bg->c:0)); + XSetBackground(stddpy, stdgc, wc->bg->c); + } +} + +void getdisplay(w, answer) +wbp w; +char *answer; + { + char *tmp; + wdp wd = w->window->display; + if (!strcmp(wd->name, "")) { + if ((tmp = getenv("DISPLAY")) != NULL) + sprintf(answer, "%s", tmp); + else + *answer = '\0'; + } + else sprintf(answer, "%s", wd->name); + } + +int getvisual(w, answer) +wbp w; +char *answer; +{ + wdp wd = w->window->display; + Visual * v = DefaultVisual(wd->display,wd->screen); + sprintf(answer, "%d,%d,%d", v->class, v->bits_per_rgb, v->map_entries ); + return Succeeded; +} +/* + * getpos() - update the window state's notion of its current position + */ +int getpos(w) +wbp w; +{ + Window garbage1, garbage2; + int root_x, root_y, win_x, win_y; + unsigned int key_buttons; + STDLOCALS(w); + if (!stdwin) return Failed; + /* + * This call is made because it is guaranteed to generate + * a synchronous request of the server, not just ask Xlib + * what the window position was last it knew. + */ + if (XQueryPointer(stddpy, stdwin, &garbage1, &garbage2, + &root_x, &root_y, &win_x, &win_y, &key_buttons) == + False) { + return Failed; + } + ws->posx = root_x - win_x; + ws->posy = root_y - win_y; + return Succeeded; +} + +void getfg(w, answer) +wbp w; +char *answer; +{ + sprintf(answer, "%s", w->context->fg->name); +} + +void getbg(w, answer) +wbp w; +char *answer; +{ + sprintf(answer, "%s", w->context->bg->name); +} + +void getlinestyle(w, answer) +wbp w; +char *answer; +{ + wcp wc = w->context; + sprintf(answer,"%s", + (wc->linestyle==LineSolid)?"solid": + ((wc->linestyle==LineOnOffDash)?"dashed":"striped")); +} + +void getfntnam(w, answer) +wbp w; +char *answer; +{ + sprintf(answer,"%s", w->context->font->name); +} + +void getpointername(w, answer) +wbp w; +char *answer; +{ + strcpy(answer, si_i2s(cursorsyms, 2 * w->window->theCursor)); +} + +void getdrawop(w, answer) +wbp w; +char *answer; +{ + char *s; + if (ISXORREVERSE(w)) s = "reverse"; + else s = si_i2s(drawops, w->context->drawop); + if (s) sprintf(answer, "%s", s); + else strcpy(answer, "copy"); +} + +void geticonic(w, answer) +wbp w; +char *answer; +{ + switch (w->window->iconic) { + case RootState: + sprintf(answer, "root"); + break; + case NormalState: + sprintf(answer, "window"); + break; + case IconicState: + sprintf(answer, "icon"); + break; + default: + sprintf(answer, "???"); + } +} + +/* + * Set the window's font by name. + */ +int setfont(w,s) +wbp w; +char **s; + { + wfp tmp; + STDLOCALS(w); + + /* could free up previously allocated font here */ + + Protect(tmp = alc_font(w,s), return Failed); + wc->font = tmp; + + if (stdgc != NULL) + XSetFont(stddpy, stdgc, wc->font->fsp->fid); + + if (stdpix == (Pixmap) NULL) { + ws->y = wc->font->fsp->max_bounds.ascent; + ws->x = 0; + } + return Succeeded; + } + +/* + * callback procedures + */ + +static int handle_exposures(w, event) +wbp w; +XExposeEvent *event; + { + int returnval; + STDLOCALS(w); + + returnval = ISEXPOSED(w); + SETEXPOSED(w); + if (stdwin && !ISZOMBIE(w)) { + if (wc->drawop != GXcopy) + XSetFunction(stddpy, stdgc, GXcopy); + if (wc->clipw >= 0) + unsetclip(w); + XCopyArea(stddpy, stdpix, stdwin, stdgc, event->x,event->y, + event->width,event->height, event->x,event->y); + if (wc->clipw >= 0) + setclip(w); + if (wc->drawop != GXcopy) + XSetFunction(stddpy,stdgc,wc->drawop); + } + return returnval; + } +#ifndef min +#define min(x,y) (((x)<(y))?(x):(y)) +#define max(x,y) (((x)>(y))?(x):(y)) +#endif + +/* + * resizePixmap(w,width,height) -- ensure w's backing pixmap is at least + * width x height pixels. + * + * Resizes the backing pixmap, if needed. Called when X resize events + * arrive, as well as when programs make explicit resize requests. + * + * Returns 0 on failure. + */ +int resizePixmap(w,width,height) +wbp w; +int width; +int height; + { + Pixmap p; + STDLOCALS(w); + if (ws->pix == (Pixmap) NULL) return 1; + if ((width > ws->pixwidth) || (height > ws->pixheight)) { + int x = ws->pixwidth, y = ws->pixheight; + + ws->pixheight = max(ws->pixheight, height); + ws->pixwidth = max(ws->pixwidth, width); + p = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), ws->pixwidth, + ws->pixheight, DefaultDepth(stddpy,wd->screen)); + if (p == (Pixmap) NULL) + return 0; + + /* + * This staggering amount of redudancy manages to make sure the new + * pixmap gets initialized including areas not in the old pixmap. + * The window is redrawn. + */ + XSetForeground(stddpy, stdgc, wc->bg->c); + if (wc->drawop != GXcopy) + XSetFunction(stddpy, stdgc, GXcopy); + if (wc->fillstyle != FillSolid) + XSetFillStyle(stddpy, stdgc, FillSolid); + if (wc->clipw >= 0) + unsetclip(w); + + if (width > x) { + XFillRectangle(stddpy, p, stdgc, x, 0, width-x, ws->pixheight); + if (stdwin != (Window) NULL) + XFillRectangle(stddpy,stdwin,stdgc, x, 0, width-x, ws->pixheight); + } + if (height > y) { + XFillRectangle(stddpy, p, stdgc, 0, y, x, height - y); + if (stdwin != (Window) NULL) + XFillRectangle(stddpy, stdwin, stdgc, 0, y, x, height - y); + } + XSetForeground(stddpy, stdgc, wc->fg->c ^ (ISXORREVERSE(w)?wc->bg->c:0)); + XCopyArea(stddpy, stdpix, p, stdgc, 0, 0, x, y, 0, 0); + if (wc->drawop != GXcopy) + XSetFunction(stddpy,stdgc,wc->drawop); + if (wc->fillstyle != FillSolid) + XSetFillStyle(stddpy, stdgc, wc->fillstyle); + if (wc->clipw >= 0) + setclip(w); + + XFreePixmap(stddpy, stdpix); /* free old pixmap */ + ws->pix = p; + } + return 1; + } + +/* + * Resize operations are made as painless as possible, but the + * user program is informed anyhow. The integer coordinates are + * the new size of the window, in pixels. + */ +static int handle_config(w, event) +wbp w; +XConfigureEvent *event; + { + struct descrip d; + STDLOCALS(w); + + /* + * Update X-Icon's information about the window's configuration + */ + ws->x = min(ws->x, event->width - FWIDTH(w)); + ws->y = min(ws->y, event->height); + + ws->posx = event->x; + ws->posy = event->y; + + /* + * If this was not a resize, drop it + */ + if ((event->width == ws->width) && (event->height == ws->height)) + return 1; + + ws->width = event->width; + ws->height = event->height; + + if (! resizePixmap(w, event->width, event->height)) return 0; + + /* + * The initial configure event generates no Icon-level "events" + */ + if (!ISEXPOSED(w)) + return 1; + + MakeInt(RESIZED, &d); + qevent(w->window, &d, ws->width, ws->height, ~(uword)0, 0); + return 1; + } + +/* + * Queue up characters for keypress events. + */ +static void handle_keypress(w,event) +wbp w; +XKeyEvent *event; + { + int i,j; + char s[10]; + struct descrip d; + KeySym k; + + w->window->pointerx = event->x; + w->window->pointery = event->y; + + switch (i=translate_key_event(event, s, &k)) { + case -1: + return; + case 0: + MakeInt(k, &d); + qevent(w->window, &d, event->x, event->y, + (uword)event->time, event->state); + break; + default: + StrLen(d) = 1; + for (j = 0; j < i; j++) { + StrLoc(d) = (char *)&allchars[s[j] & 0xFF]; + qevent(w->window, &d, event->x, event->y, + (uword)event->time, event->state); + } + } + } + +#define swap(a,b) { tmp = a; a = b; b = tmp; } +/* + * Handle button presses and drag events. In the case of drags, we should + * really be looking at an XMotionEvent instead of an XButtonEvent, but + * the structures are identical up to the button field (which we do not + * examine for drag events). Mouse coordinates are queued up after the event. + */ +static void handle_mouse(w,event) +wbp w; +XButtonEvent *event; + { + static unsigned int buttonorder[3] = + { Button1Mask, Button2Mask, Button3Mask }; + unsigned int tmp; + int eventcode = 0; + struct descrip d; + + if (event->type == MotionNotify) { + if (event->state | buttonorder[0]) { + if (buttonorder[0] == Button1Mask) + eventcode = MOUSELEFTDRAG; + else if (buttonorder[0] == Button2Mask) + eventcode = MOUSEMIDDRAG; + else + eventcode = MOUSERIGHTDRAG; + } + else if (event->state | buttonorder[1]) { + if (buttonorder[1] == Button1Mask) + eventcode = MOUSELEFTDRAG; + else if (buttonorder[1] == Button2Mask) + eventcode = MOUSEMIDDRAG; + else + eventcode = MOUSERIGHTDRAG; + } + else if (event->state | buttonorder[2]) { + if (buttonorder[2] == Button1Mask) + eventcode = MOUSELEFTDRAG; + else if (buttonorder[2] == Button2Mask) + eventcode = MOUSEMIDDRAG; + else + eventcode = MOUSERIGHTDRAG; + } + } + else switch (event->button) { + case Button1: { + eventcode = MOUSELEFT; + if (buttonorder[2] == Button1Mask) + swap(buttonorder[1],buttonorder[2]); + if (buttonorder[1] == Button1Mask) + swap(buttonorder[0],buttonorder[1]); + break; + } + case Button2: { + eventcode = MOUSEMID; + if (buttonorder[2] == Button2Mask) + swap(buttonorder[1],buttonorder[2]); + if (buttonorder[1] == Button2Mask) + swap(buttonorder[0],buttonorder[1]); + break; + } + case Button3: { + eventcode = MOUSERIGHT; + if (buttonorder[2] == Button3Mask) + swap(buttonorder[1],buttonorder[2]); + if (buttonorder[1] == Button3Mask) + swap(buttonorder[0],buttonorder[1]); + break; + } + } + if (event->type == ButtonRelease) { + eventcode -= (MOUSELEFT - MOUSELEFTUP); + swap(buttonorder[0],buttonorder[1]); + swap(buttonorder[1],buttonorder[2]); + } + + w->window->pointerx = event->x; + w->window->pointery = event->y; + MakeInt(eventcode,&d); + qevent(w->window, &d, event->x, event->y, (uword)event->time, event->state); + } + + +/* + * fill a series of rectangles + */ +void fillrectangles(w, recs, nrecs) +wbp w; +XRectangle *recs; +int nrecs; + { + STDLOCALS(w); + + /* + * Free colors if drawop=copy, fillstyle~=masked, no clipping, + * and a single rectangle that fills the whole window. + */ + if (!RECX(*recs) && !RECY(*recs) && RECWIDTH(*recs) >= ws->width && + RECHEIGHT(*recs) >= ws->height && nrecs == 1 && + wc->drawop == GXcopy && wc->fillstyle != FillStippled && wc->clipw < 0) { + RECWIDTH(*recs) = ws->pixwidth; /* fill hidden part */ + RECHEIGHT(*recs) = ws->pixheight; + free_xcolors(w, 0); /* free old colors */ + } + RENDER2(XFillRectangles, recs, nrecs); + } + +/* + * erase an area + */ +void eraseArea(w,x,y,width,height) +wbp w; +int x, y, width, height; + { + STDLOCALS(w); + + /* + * if width >= window width or height >= window height, clear any + * offscreen portion as well in order to allow the freeing of colors. + */ + if (x + width >= ws->width) width = ws->pixwidth - x; + if (y + height >= ws->height) height = ws->pixheight - y; + + /* + * fill the rectangle with the background color + */ + XSetForeground(stddpy, stdgc, wc->bg->c); + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy); + if (wc->fillstyle != FillSolid) XSetFillStyle(stddpy, stdgc, FillSolid); + RENDER4(XFillRectangle, x, y, width, height); + XSetForeground(stddpy, stdgc, wc->fg->c ^ (ISXORREVERSE(w)?wc->bg->c:0)); + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop); + if (wc->fillstyle != FillSolid) XSetFillStyle(stddpy, stdgc, wc->fillstyle); + + /* + * if the entire window is cleared, free up colors + */ + if (!x && !y && width >= ws->pixwidth && height >= ws->pixheight && + wc->clipw < 0) + free_xcolors(w, 0); + } + +/* + * copy an area + */ +int copyArea(w,w2,x,y,width,height,x2,y2) +wbp w, w2; +int x, y, width, height, x2, y2; + { + int lpad, rpad, tpad, bpad; + Pixmap src; + wsp ws1 = w->window, ws2 = w2->window; + wclrp cp1, cp2 = NULL, *cpp; + STDLOCALS(w2); + + if (w->window->display->display != w2->window->display->display) { + wdp wd1 = ws1->display; + unsigned long c = 0; + int i, j; + Display *d1 = wd1->display; + XColor clr; + XImage *xim; + + /* + * Copying is between windows on two different displays. + */ + if (x<0 || y<0 || x+width > ws1->pixwidth || y+height > ws1->pixheight) + return Failed; /*#%#%# BOGUS, NEEDS FIXING */ + xim = XGetImage(d1, ws1->pix, x, y, width, height, + (1<<DefaultDepth(d1,wd1->screen))-1,XYPixmap); + XSetFunction(stddpy, stdgc, GXcopy); + for (i=0; i < width; i++) { + for (j=0; j < height; j++) { + clr.pixel = XGetPixel(xim, i, j); + if (cp2 != NULL && c == clr.pixel) { + XSetForeground(stddpy, stdgc, cp2->c); + RENDER2(XDrawPoint, i + x2, j + y2); + continue; + } + c = clr.pixel; + cp2 = NULL; + for (cpp = wd1->colrptrs; cpp < wd1->colrptrs+wd->numColors; cpp++){ + cp1 = *cpp; + if (cp1->c == c) { + if (cp1->name[0]=='\0') { + XQueryColor(d1, wd1->cmap, &clr); + cp1->r = clr.red; + cp1->g = clr.green; + cp1->b = clr.blue; + sprintf(cp1->name,"%d,%d,%d",cp1->r,cp1->g,cp1->b); + } + cp2 = alc_rgb(w2, cp1->name, cp1->r, cp1->g, cp1->b, 0); + if (cp2 == NULL) return Failed; + break; + } + } + if (cp2 == NULL) { + XQueryColor(d1, wd1->cmap, &clr); + cp2 = alc_rgb(w2, "unknown", clr.red, clr.green, clr.blue, 0); + } + if (cp2 == NULL) return Failed; + XSetForeground(stddpy, stdgc, cp2->c); + RENDER2(XDrawPoint, i + x2, j + y2); + } + } + XSetForeground(stddpy, stdgc, + wc->fg->c ^ (ISXORREVERSE(w2) ? wc->bg->c : 0)); + XSetFunction(stddpy, stdgc, wc->drawop); + XSync(stddpy,False); + XDestroyImage(xim); + } + else { + /* + * Copying is between windows on one display, perhaps the same window. + */ + src = ws1->pix; + if (src != stdpix) { + /* copying between different windows; handle color bookkeeping */ + if (!x2 && !y2 && + ((width >= ws2->pixwidth) || !width) && + ((height >= ws2->pixheight) || !height) && w2->context->clipw < 0) + free_xcolors(w2, 0); + copy_colors(w, w2); + } + + XSetForeground(stddpy, stdgc, wc->bg->c); + XSetFunction(stddpy, stdgc, GXcopy); + + if (x+width<0 || y+height<0 || x>=ws1->pixwidth || y>=ws1->pixheight) { + /* source is entirely offscreen */ + RENDER4(XFillRectangle, x2, y2, width, height); + } + else { + /* + * Check for source partially offscreen, but copy first and + * fill later in case the source and destination overlap. + */ + lpad = rpad = tpad = bpad = 0; + if (x < 0) { /* source extends past left edge */ + lpad = -x; + width -= lpad; + x2 += lpad; + x = 0; + } + if (x + width > ws1->pixwidth) { /* source extends past right edge */ + rpad = x + width - ws1->pixwidth; + width -= rpad; + } + if (y < 0) { /* source extends above top edge */ + tpad = -y; + height -= tpad; + y2 += tpad; + y = 0; + } + if (y + height > ws1->pixheight) { /* source extends below bottom */ + bpad = y + height - ws1->pixheight; + height -= bpad; + } + /* + * Copy the area. + */ + if (stdwin) + XCopyArea(stddpy, src, stdwin, stdgc, x, y, width, height, x2, y2); + XCopyArea(stddpy, src, stdpix, stdgc, x, y, width, height, x2, y2); + /* + * Fill any edges not provided by source. + */ + if (lpad > 0) + RENDER4(XFillRectangle, x2-lpad, y2-tpad, lpad, tpad+height+bpad); + if (rpad > 0) + RENDER4(XFillRectangle, x2+width, y2-tpad, rpad, tpad+height+bpad); + if (tpad > 0) + RENDER4(XFillRectangle, x2, y2-tpad, width, tpad); + if (bpad > 0) + RENDER4(XFillRectangle, x2, y2+height, width, bpad); + } + + XSetForeground(stddpy,stdgc,wc->fg->c^(ISXORREVERSE(w2) ? wc->bg->c :0)); + XSetFunction(stddpy, stdgc, wc->drawop); + } + return Succeeded; + } + +int getdefault(w, prog, opt, answer) +wbp w; +char *prog, *opt, *answer; + { + char *p; + STDLOCALS(w); + + + if ((p = XGetDefault(stddpy,prog,opt)) == NULL) + return Failed; + strcpy(answer, p); + return Succeeded; + } + + +/* + * Allocate a mutable color + */ +int mutable_color(w, argv, ac, retval) +wbp w; +dptr argv; +int ac; +int *retval; + { + XColor colorcell; + LinearColor clr; + unsigned long plane_masks[1], pixels[1]; + char *colorname; + tended char *str; + int i; + { + STDLOCALS(w); + + if (!XAllocColorCells(stddpy,wd->cmap,False,plane_masks,0,pixels,1)) { + /* + * try again with a virtual colormap + */ + if (!go_virtual(w) || + !XAllocColorCells(stddpy,wd->cmap,False,plane_masks,0,pixels,1)) + return Failed; /* cannot allocate an entry */ + } + + /* + * allocate a slot in wdisplay->colors and wstate->theColors arrays + */ + i = alc_centry(wd); + if (i == 0) + return Failed; + wd->colrptrs[i]->type = MUTABLE; + wd->colrptrs[i]->c = pixels[0]; + + /* save color index as "name", followed by a null string for value */ + colorname = wd->colrptrs[i]->name; + sprintf(colorname, "%ld", -pixels[0] - 1); /* index is name */ + colorname = colorname + strlen(colorname) + 1; + *colorname = '\0'; /* value unknown */ + + if (ws->numColors < WMAXCOLORS) { + if (ws->theColors == NULL) { + ws->theColors = (short *)calloc(WMAXCOLORS, sizeof(short)); + if (ws->theColors == NULL) + return Error; + } + ws->theColors[ws->numColors++] = i; + } + + if (ac > 0) { /* set the color */ + if (ac != 1) return Error; + /* + * old-style check for C integer + */ + else if (argv[0].dword == D_Integer) {/* check for color cell */ + if (IntVal(argv[0]) >= 0) + return Failed; /* must be negative */ + colorcell.pixel = -IntVal(argv[0]) - 1; + XQueryColor(stddpy, wd->cmap, &colorcell); + clr = lcolor(w, colorcell); + sprintf(colorname, "%ld,%ld,%ld", clr.red, clr.green, clr.blue); + } + else { + if (!cnv:C_string(argv[0],str)) { + ReturnErrVal(103,argv[0], Error); + } + if (parsecolor(w, str, &clr.red, &clr.green, &clr.blue) != Succeeded) { + free_xcolor(w, pixels[0]); + return Failed; /* invalid color specification */ + } + strcpy(colorname, str); + colorcell = xcolor(w, clr); + } + colorcell.pixel = pixels[0]; + XStoreColor(stddpy, wd->cmap, &colorcell); + } + + *retval = (-pixels[0] - 1); + return Succeeded; + } + } + +char *get_mutable_name(w, mute_index) +wbp w; +int mute_index; + { + wdp dp; + Display *d; + int i; + char *colorname; + + dp = w->window->display; + d = dp->display; + + for (i = 2; i < dp->numColors; i++) + if (dp->colrptrs[i]->type == MUTABLE + && dp->colrptrs[i]->c == - mute_index - 1) + break; + if (i == dp->numColors) + return NULL; + colorname = dp->colrptrs[i]->name; /* color name field */ + colorname = colorname + strlen(colorname) + 1; /* set value follows */ + return colorname; + } + +int set_mutable(w, i, s) +wbp w; +int i; +char *s; + { + LinearColor clr; + XColor colorcell; + wdp dp = w->window->display; + + if (parsecolor(w, s, &clr.red, &clr.green, &clr.blue) != Succeeded) + return Failed; /* invalid color specification */ + colorcell = xcolor(w, clr); + colorcell.pixel = -i - 1; + XStoreColor(dp->display, dp->cmap, &colorcell); + return Succeeded; + } + +void free_mutable(w, mute_index) +wbp w; +int mute_index; + { + wdp dp; + Display *d; + int i; + + dp = w->window->display; + d = dp->display; + + for (i = 2; i < dp->numColors; i++) + if (dp->colrptrs[i]->type == MUTABLE + && dp->colrptrs[i]->c == - mute_index - 1) + break; + if (i != dp->numColors) + free_xcolor(w, dp->colrptrs[i]->c); + } + + +void freecolor(w, s) +wbp w; +char *s; + { + wdp dp; + Display *d; + int i; + LinearColor clr; + XColor color; + + if (parsecolor(w, s, &clr.red, &clr.green, &clr.blue) != Succeeded) + return; + dp = w->window->display; + d = dp->display; + color = xcolor(w, clr); + + for (i = 2; i < dp->numColors; i++) + if (dp->colrptrs[i]->r == color.red && dp->colrptrs[i]->g == color.green + && dp->colrptrs[i]->b == color.blue && dp->colrptrs[i]->type != MUTABLE) + break; + if (i != dp->numColors) + free_xcolor(w, dp->colrptrs[i]->c); + } + +/* + * Draw a bilevel image + */ +int blimage(w, x, y, width, height, ch, s, len) +wbp w; +int x, y, width, height, ch; +unsigned char *s; +word len; + { + unsigned int m, msk1, c, ix, iy; + long fg, bg; + XImage *im; + STDLOCALS(w); + + /* + * Get an XImage structure and free the old color set if possible. + */ + im = getximage(w, x, y, width, height, ch == TCH1); + if (im == NULL) + return Error; + + /* + * Read the image string and set the pixel values. Note that + * the hex digits in sequence fill the rows *right to left*. + */ + m = width % 4; + if (m == 0) + msk1 = 8; + else + msk1 = 1 << (m - 1); /* mask for first byte of row */ + + fg = wc->fg->c; + bg = wc->bg->c; + ix = width; + iy = 0; + m = msk1; + while (len--) { + if (isxdigit(c = *s++)) { /* if hexadecimal character */ + if (!isdigit(c)) /* fix bottom 4 bits if necessary */ + c += 9; + while (m > 0) { /* set (usually) 4 pixel values */ + --ix; + if (c & m) + XPutPixel(im, ix, iy, fg); + else if (ch != TCH1) /* if zeroes aren't transparent */ + XPutPixel(im, ix, iy, bg); + m >>= 1; + } + if (ix == 0) { /* if end of row */ + ix = width; + iy++; + m = msk1; + } + else + m = 8; + } + } + if (ix > 0) /* pad final row if incomplete */ + while (ix < width) + XPutPixel(im, ix++, iy, bg); + + /* + * Put it on the screen. + */ + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy); + RENDER7(XPutImage, im, 0, 0, x, y, width, height); + XDestroyImage(im); + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop); + return Succeeded; + } + +/* + * Draw a character-per-pixel image + */ +int strimage(w, x, y, width, height, e, s, len, on_icon) +wbp w; +int x, y, width, height; +struct palentry *e; +unsigned char *s; +word len; +int on_icon; + { + int c, v, ret, trans; + unsigned int r, g, b, ix, iy; + wclrp cp, cplist[256]; + char tmp[24]; + XImage *im; + STDLOCALS(w); + + /* + * Get an XImage structure and free the old color set if possible. + */ + trans = 0; + for (c = 0; c < 256; c++) + trans |= e[c].used && e[c].transpt; + im = getximage(w, x, y, width, height, trans); + if (im == NULL) + return -1; + + /* + * Allocate the colors we need. Use black or white if unsuccessful. + */ + ret = 0; + for (c = 0; c < 256; c++) + if (e[c].used && e[c].valid) { + r = e[c].clr.red; + g = e[c].clr.green; + b = e[c].clr.blue; + sprintf(tmp, "%d,%d,%d", r, g, b); + cp = alc_rgb(w, tmp, r, g, b, 0); + if (cp == NULL) { + ret++; + if ((0.299 * r + 0.587 * g + 0.114 * b) > 32767) + cp = alc_rgb(w, "white", 65535, 65535, 65535, 0); + else + cp = alc_rgb(w, "black", 0, 0, 0, 0); + } + cplist[c] = cp; + } + + /* + * Read the image string and set the pixel values. + */ + ix = iy = 0; + while (len--) { + c = *s++; + v = e[c].valid; + if (v) /* put char if valid */ + XPutPixel(im, ix, iy, cplist[c]->c); + if (v || e[c].transpt) { /* advance if valid or transparent */ + if (++ix >= width) { + ix = 0; /* reset for new row */ + iy++; + } + } + } + if (ix > 0) /* pad final row if incomplete */ + while (ix < width) + XPutPixel(im, ix++, iy, wc->bg->c); + + /* + * Put it on the screen. + */ + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy); + if (on_icon) { + if (ws->iconwin == (Window) NULL) makeIcon(w, 0, 0); + XPutImage(stddpy, ws->iconwin, stdgc, im, 0, 0, x, y, width, height); + XPutImage(stddpy, ws->iconpix, stdgc, im, 0, 0, x, y, width, height); + } + else { + XPutImage(stddpy, ws->pix, stdgc, im, 0, 0, x, y, width, height); + if (ws->win) + XCopyArea(stddpy, ws->pix, ws->win, stdgc, x, y, width, height, x, y); + } + XDestroyImage(im); + if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop); + return ret; + } + +/* + * capture(w, x, y, width, height, data) -- get image region. + * + * Stores the specified subimage in data as 15-bit linear color. + */ +int capture(w, x, y, width, height, data) +wbp w; +int x, y, width, height; +short *data; + { + Visual *v; + XImage *im; + XColor colorcell; + LinearColor lc; + wclrp *cpp; + unsigned char cmap[256]; + short *cval; + int i, r, g, b, ncolors; + unsigned long px, clist[GIFMAX], *lp, *ckey; + double gamma = w->context->gamma; + STDLOCALS(w); + + /* + * Get an XImage structure containing window pixel values. + */ + im = getximage(w, x, y, width, height, 1); + if (!im) + return 0; + + /* + * Make a mapping table from X color to 5-bit linear color. + */ + for (i = 0; i < 256; i++) + cmap[i] = 31 * pow(i / 255., gamma) + 0.5; + + /* + * Translate the colors and store in the data buffer. + */ + v = wd->visual; + if (v->class == TrueColor && v->red_mask == 0x00FF0000L + && v->green_mask == 0x0000FF00L && v->blue_mask == 0x000000FFL) { + /* + * 24-bit RGB is decomposed and mapped directly + */ + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + px = XGetPixel(im, x, y); + r = cmap[(px >> 16) & 0xFF]; + g = cmap[(px >> 8) & 0xFF]; + b = cmap[px & 0xFF]; + *data++ = (r << 10) | (g << 5) | b; + } + } + } + else { + /* + * General case uses a cache to improve performance. + */ + #define CCACHE 4987 /* cache size; should be odd */ + ckey = calloc(CCACHE, sizeof(ckey[0])); + cval = calloc(CCACHE, sizeof(cval[0])); + if (!ckey || !cval) + return 0; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + px = XGetPixel(im, x, y); /* get pixel value */ + i = px % CCACHE; /* get cache index */ + if (ckey[i] != px) { /* if color not cached */ + colorcell.pixel = px; + colorcell.flags = DoRed | DoGreen | DoBlue; + XQueryColor(stddpy, wd->cmap, &colorcell); /* costly */ + ckey[i] = px; + cval[i] = (cmap[colorcell.red >> 8] << 10) | + (cmap[colorcell.green >> 8] << 5) | cmap[colorcell.blue >> 8]; + } + *data++ = cval[i]; /* save rgb15 color value */ + } + } + free(cval); + free(ckey); + } + XDestroyImage(im); + return 1; + } + +/* + * Create an XImage structure corresponding to subimage (x, y, w, h). + * If init is nonzero, initialize it with current contents. + * If init is zero and (x,y,w,h) fills the window, free existing color set. + */ +static XImage *getximage(w, x, y, width, height, init) +wbp w; +int x, y, width, height, init; + { + int tx, ty; + XImage *im; + STDLOCALS(w); + + im = XCreateImage(stddpy, DefaultVisual(stddpy, wd->screen), + DefaultDepth(stddpy, wd->screen), ZPixmap, 0, NULL, width, height, 32, 0); + if (im == NULL) + return NULL; + im->data = malloc(im->bytes_per_line * height); + if (im->data == NULL) { + XDestroyImage(im); + return NULL; + } + + if (!init) { + if (x <= 0 && y <= 0 && x + width >= ws->pixwidth && + y + height >= ws->pixheight && wc->clipw < 0) + free_xcolors(w, 0); + return im; + } + + tx = ty = 0; + if (x < 0) { tx -= x; width += x; x = 0; } + if (y < 0) { ty -= y; height += y; y = 0; } + if (x + width > ws->width) { width = ws->width - x; } + if (y + height > ws->height) { height = ws->height - y; } + if (width > 0 && height > 0) + XGetSubImage(stddpy, stdpix, x, y, width, height, AllPlanes, ZPixmap, + im, tx, ty); + return im; + } + +int readimage(w, filename, x, y, status) +wbp w; +char *filename; +int x, y, *status; + { + Pixmap p; + unsigned int width, height; + STDLOCALS(w); + if (!x && !y) + p = loadimage(w, filename, &height, &width, 1, status); + else + p = loadimage(w, filename, &height, &width, 0, status); + if (p == (Pixmap) NULL) return Failed; + + if (wc->drawop != GXcopy) + XSetFunction(stddpy, stdgc, GXcopy); + if (stdwin) + XCopyArea(stddpy, p, stdwin, stdgc, 0, 0, width, height, x, y); + XCopyArea(stddpy, p, stdpix, stdgc, 0, 0, width, height, x, y); + if (wc->drawop != GXcopy) + XSetFunction(stddpy,stdgc,wc->drawop); + + /* + * Make sure previous ops on p are complete, then free it. + */ + XSync(stddpy, False); + XFreePixmap(stddpy, p); + return Succeeded; + } + + +/* + * Initialize client for producing pixels from a window + */ +int getpixel_init(w, imem) +wbp w; +struct imgmem *imem; + { + STDLOCALS(w); + + if (imem->width <= 0 || imem->height <= 0) { + imem->im = NULL; + return Succeeded; + } + + imem->im = XGetImage(stddpy, stdpix, + imem->x, imem->y, imem->width, imem->height, + (1 << DefaultDepth(stddpy, wd->screen))-1, XYPixmap); + + if (imem->im == NULL) return Failed; + return Succeeded; + } + +int getpixel_term(w, imem) +wbp w; +struct imgmem *imem; + { + if (imem->im != NULL) + XDestroyImage(imem->im); + return Succeeded; + } + +/* + * Return pixel (x,y) from a window in long value (rv) + */ +int getpixel(w, x, y, rv, s, imem) +wbp w; +int x, y; +long *rv; +char *s; +struct imgmem *imem; + { + XColor colorcell; + LinearColor clr; + wclrp *cpp; + unsigned long c; + STDLOCALS(w); + + if (x < imem->x || x >= imem->x + imem->width || + y < imem->y || y >= imem->y + imem->height) + c = colorcell.pixel = wc->bg->c; + else + c = colorcell.pixel = XGetPixel(imem->im, x - imem->x, y - imem->y); + *rv = 0xff000000; + + for (cpp = wd->colrptrs ; cpp < wd->colrptrs + wd->numColors; cpp++) { + if ((*cpp)->c == c) { + if ((*cpp)->type == MUTABLE) + *rv = -c - 1; + else { + *rv = 1; + colorcell.red = (*cpp)->r; + colorcell.green = (*cpp)->g; + colorcell.blue = (*cpp)->b; + clr = lcolor(w, colorcell); + sprintf(s, "%ld,%ld,%ld", clr.red, clr.green, clr.blue); + } + break; + } + } + if (*rv == 0xff000000) { + XQueryColor(stddpy, wd->cmap, &colorcell); + *rv = 1; + clr = lcolor(w, colorcell); + sprintf(s, "%ld,%ld,%ld", clr.red, clr.green, clr.blue); + } + return Succeeded; + } + + +int query_pointer(w, pp) +wbp w; +XPoint *pp; + { + Display *theDisplay; + Window theWindow; + Window garbage1, garbage2; + int root_x, root_y, win_x, win_y; + unsigned int key_buttons; + + theDisplay = w->window->display->display; + theWindow = w->window->win; + if (theWindow == (Window) NULL) return Failed; + + XQueryPointer(theDisplay, theWindow, &garbage1, &garbage2, + &root_x, &root_y, &win_x, &win_y, &key_buttons); + pp->x = w->window->pointerx = win_x; + pp->y = w->window->pointery = win_y; + return Succeeded; + } + +int query_rootpointer(pp) +XPoint *pp; + { + Display *theDisplay; + Window theWindow; + Window garbage1, garbage2; + int root_x, root_y, win_x, win_y; + unsigned int key_buttons; + wdp wd; + if (wdsplys == NULL) { + /* + * Initialize the window system + */ + Protect(wd = alc_display(NULL), return Failed); + + theDisplay = wd->display; + theWindow = DefaultRootWindow(wd->display); + } + else { + wd = wdsplys; + theDisplay = wd->display; + theWindow = DefaultRootWindow(wd->display); + } + XQueryPointer(theDisplay, theWindow, &garbage1, &garbage2, + &root_x, &root_y, &win_x, &win_y, &key_buttons); + pp->x = root_x; + pp->y = root_y; + return Succeeded; + } + + +int patbits[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFE,0xFF,0xEF,0xFF,0xFE,0xFF,0xEF,0xFF, + 0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD, + 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA, + 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44, + 0x01,0x00,0x10,0x00,0x01,0x00,0x10,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10, + 0x82,0x44,0x28,0x10,0x28,0x44,0x82,0x01, + + 0x0F,0x0F,0x0F,0x0F,0xF0,0xF0,0xF0,0xF0, + 0x1B,0x18,0x81,0xB1,0x36,0x06,0x60,0x63, + 0x02,0x02,0x05,0xF8,0x20,0x20,0x50,0x8F, + 0x03,0x84,0x48,0x30,0x03,0x84,0x48,0x30, +}; + +/* + * pattern symbols + */ +stringint siPatternSyms[] = { + {0, 16}, + { "black", 0}, + { "checkers", 12}, + { "darkgray", 2}, + { "diagonal", 8}, + { "grains", 13}, + { "gray", 3}, + { "grid", 10}, + { "horizontal",9}, + { "lightgray", 4}, + { "scales", 14}, + { "trellis", 11}, + { "vertical", 7}, + { "verydark", 1}, + { "verylight", 5}, + { "waves", 15}, + { "white", 6}, +}; + +/* + * SetPattern + */ +int SetPattern(w, name, len) +wbp w; +char *name; +int len; + { + int width, nbits; + int i; + int symbol; + C_integer v, bits[MAXXOBJS]; + Pixmap p; + char data[MAXXOBJS]; + char *buf = data; + STDLOCALS(w); + + if (wc->patternname != NULL) + free(wc->patternname); + wc->patternname = malloc(len+1); + if (wc->patternname == NULL) ReturnErrNum(305, Error); + strncpy(wc->patternname, name, len); + wc->patternname[len] = '\0'; + + /* + * If the pattern starts with a number it is a width , bits encoding + */ + if ((len > 0) && isdigit(name[0])) { + nbits = MAXXOBJS; + switch (parsepattern(name, len, &width, &nbits, bits)) { + case Failed: + return Failed; + case Error: + ReturnErrNum(145, Error); + } + if (!stdgc) return Succeeded; + return SetPatternBits(w, width, bits, nbits); + } + + /* + * Otherwise, it is a named pattern. Find the symbol id. + */ + if ((symbol = si_s2i(siPatternSyms, wc->patternname)) >= 0) { + if (!stdgc) return Succeeded; + for(i = 0; i < 8; i++) { + v = patbits[symbol * 8 + i]; + *buf++ = v; + } + p = XCreateBitmapFromData(stddpy, stdpix, data, 8, 8); + XSetStipple(stddpy, stdgc, p); + XSync(stddpy, False); + XFreePixmap(stddpy, p); + return Succeeded; + } + return Failed; + } + +int SetPatternBits(w, width, bits, nbits) +wbp w; +int width; +C_integer *bits; +int nbits; + { + C_integer v; + int i, j; + Pixmap p; + char data[MAXXOBJS]; + char *buf = data; + STDLOCALS(w); + + for(i = 0; i < nbits; i++) { + v = bits[i]; + for(j=0; j<width; j+=8) { + *buf++ = v; + v >>= 8; + } + } + + p = XCreateBitmapFromData(stddpy, stdpix, data, width, nbits); + XSetStipple(stddpy, stdgc, p); + XSync(stddpy, False); + XFreePixmap(stddpy, p); + return Succeeded; + } + + + +/* + * remap a window ... this time with an iconwin + */ +int remap(w,x,y) +wbp w; +int x,y; + { + XSizeHints size_hints; + XWMHints *wmhints; + STDLOCALS(w); + + XGetSizeHints(stddpy, stdwin, &size_hints, XA_WM_NORMAL_HINTS); + wmhints = XGetWMHints(stddpy, stdwin); + if (ws->iconwin) + XDestroyWindow(stddpy, ws->iconwin); + if (stdwin) + XDestroyWindow(stddpy, stdwin); + + ws->win = XCreateSimpleWindow(stddpy, DefaultRootWindow(stddpy), + ws->posx, ws->posy, ws->width, + ws->height, 4, wc->fg->c, wc->bg->c); + XSetStandardProperties(stddpy, ws->win, ws->windowlabel, + ws->iconlabel, 0, 0, 0, &size_hints); + XSelectInput(stddpy, ws->win, ExposureMask | KeyPressMask | + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + StructureNotifyMask); + + ws->iconwin = XCreateSimpleWindow(stddpy, DefaultRootWindow(stddpy), + ws->iconx, ws->icony, ws->iconw, + ws->iconh, 2, wc->fg->c, wc->bg->c); + XSelectInput(stddpy, ws->iconwin, + ExposureMask | KeyPressMask | ButtonPressMask); + + wmhints->flags |= IconPositionHint; + wmhints->icon_x = x; + wmhints->icon_y = y; + wmhints->initial_state = ws->iconic; + wmhints->icon_window = ws->iconwin; + wmhints->flags |= IconWindowHint; + XSetWMHints(stddpy, ws->win, wmhints); + CLREXPOSED(w); + XMapWindow(stddpy, ws->win); + if (ws->iconic == NormalState) { + while (!ISEXPOSED(w)) + if (pollevent() == -1) return -1; + } + ws->iconx = x; + ws->icony = y; + XSync(stddpy, False); + XFree((char *)wmhints); + return 1; + } + + +int seticonimage(w, dp) +wbp w; +dptr dp; + { + int status; + Pixmap pix; + tended char *tmp; + { + STDLOCALS(w); + /* + * get the preloaded (in another window value) pixmap image + */ + if (is:file(*dp) && (BlkLoc(*dp)->file.status & Fs_Window)) { + wbp x = (wbp)BlkLoc(*dp)->file.fd; + if ((ws->iconimage = salloc(x->window->windowlabel)) == NULL) + ReturnErrNum(305, Error); + pix = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), + x->window->width, x->window->height, + DefaultDepth(stddpy,wd->screen)); + + XCopyArea(stddpy, x->window->pix, pix, wd->icongc, 0, 0, + x->window->width, x->window->height, 0, 0); + if (ws->iconpix) { + XSync(stddpy, False); + XFreePixmap(stddpy, ws->iconpix); + } + ws->iconpix = pix; + ws->iconw = x->window->width; + ws->iconh = x->window->height; + if (!ws->iconx && !ws->icony) { + ws->iconx = ws->x; + ws->icony = ws->y; + } + if (remap(w,ws->iconx,ws->icony) == -1) + ReturnErrNum(144, Error); + + } + /* get the pixmap file named by x */ + else if (is:string(*dp)) { + unsigned int height, width; + if (!cnv:C_string(*dp,tmp)) + ReturnErrVal(103, *dp, Error); + + if ((ws->iconimage != NULL) && strcmp(ws->iconimage, "")) + free(ws->iconimage); + if ((ws->iconimage = salloc(tmp)) == NULL) + ReturnErrNum(305, Error); + if (ws->iconwin == (Window) NULL) makeIcon(w,0,0); + else { + pix = loadimage(w, ws->iconimage, &height, &width, 0, &status); + if (pix == (Pixmap) NULL) + return Failed; + XCopyArea(stddpy, pix, ws->iconwin, wd->icongc, + 0, 0, width, height, 0, 0); + if (ws->iconpix) { + XSync(stddpy, False); + XFreePixmap(stddpy, ws->iconpix); + } + ws->iconpix = pix; + ws->iconw = width; + ws->iconh = height; + if (remap(w,ws->iconx,ws->icony) == -1) + ReturnErrNum(144, Error); + } + } + else + return Failed; + return Succeeded; + } + } + + +/* + * dumpimage -- write an image to a disk file in an X format. + * + * Accepts only .xpm and .xbm file names, returning NoCvt for anything else. + */ + +int dumpimage(w,filename,x,y,width,height) +wbp w; +char *filename; +unsigned int x, y, height, width; + { + int status; + STDLOCALS(w); + + /* + * Check for bilevel XBM (X BitMap) format. + */ + if (!strcmp(".xbm", filename + strlen(filename) - 4) || + !strcmp(".XBM", filename + strlen(filename) - 4)) { + /* + * Write a bitmap from a "color" window (presumed to have only BW in it). + * BlackPixel ^ WhitePixel will have a 1 in the first bit in which + * they are different, so this bit is the plane we want to copy. + */ + + if (DefaultDepth(stddpy,wd->screen) != 1) { + unsigned long bw = + BlackPixel(stddpy,wd->screen) ^ WhitePixel(stddpy,wd->screen); + Pixmap p1 = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), + width, height, 1); + XGCValues xgc; + GC thinGC; + int i; + /* + * pick out the bitplane on which Black and White differ + */ + for(i=0;!((1<<i) & bw);i++); + bw &= (1<<i); + /* + * Construct a 1-bit-deep GC for use in copying the plane. + */ + xgc.foreground = BlackPixel(stddpy,wd->screen); + xgc.background = WhitePixel(stddpy,wd->screen); + thinGC = XCreateGC(stddpy,p1,GCForeground|GCBackground,&xgc); + + if (i>DefaultDepth(stddpy,wd->screen)) return Failed; + XCopyPlane(stddpy,stdpix,p1,thinGC,x,y,width,height,0,0,bw); + status= XWriteBitmapFile(stddpy, filename, p1, width, height, -1, -1); + + XSync(stddpy, False); + XFreePixmap(stddpy, p1); + XFreeGC(stddpy,thinGC); + if (status != BitmapSuccess) return Failed; + } + else { + if(x || y) { + Pixmap p1 = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), width, + height, DefaultDepth(stddpy,wd->screen)); + + XCopyArea(stddpy, stdpix, p1, stdgc, x, y, width, height, 0, 0); + XSync(stddpy, False); + + status = XWriteBitmapFile(stddpy,filename,p1,width,height,-1,-1); + + XSync(stddpy, False); + XFreePixmap(stddpy, p1); + + if (status != BitmapSuccess) return Failed; + + } + else if (XWriteBitmapFile(stddpy, filename, stdpix, + width, height, -1, -1) != BitmapSuccess) + return Failed; + + } + return Succeeded; + } + /* + * Check for XPM (color X PixMap) format. + */ + else if (!strcmp(".xpm", filename + strlen(filename) - 4) || + !strcmp(".XPM", filename + strlen(filename) - 4) || + !strcmp(".xpm.Z", filename + strlen(filename) - 6)) { +#ifdef HaveXpmFormat + /* + * Could optimize by calling XpmWriteFileFromPixmap directly on the + * stdpix... + */ + Pixmap p1 = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), width, + height, DefaultDepth(stddpy,wd->screen)); + + XCopyArea(stddpy, stdpix, p1, stdgc, x, y, width, height, 0, 0); + XSync(stddpy, False); + + status = XpmWriteFileFromPixmap(stddpy, filename, p1, + (Pixmap) NULL, NULL); + XSync(stddpy, False); + XFreePixmap(stddpy, p1); + + if (status == XpmSuccess) + return Succeeded; +#endif /* HaveXpmFormat */ + return Failed; + } + else + return NoCvt; /* not an X format -- write GIF instead */ + } + +/* + * Load an image, in any format we can figure out. + */ +Pixmap loadimage(w, filename, height, width, atorigin, status) +wbp w; +char *filename; +unsigned int *height, *width; +int atorigin; +int *status; + { + Pixmap p1, p2 = (Pixmap) NULL; + int xhot, yhot, i, j; + XGCValues gcv; + unsigned long gcmask = GCFont | GCForeground | GCBackground; + int isxbm; + STDLOCALS(w); + + if (!strcmp(".xbm", filename + strlen(filename) - 4)) + isxbm = 1; + else if (!strcmp(".xpm", filename + strlen(filename) - 4) || + !strcmp(".xpm.Z", filename + strlen(filename) - 6)) + isxbm = 0; + else { + /* + * Not sure what kind of file this is, make a guess + * For example, the format might be on the first line of the file, + * so open it up and read some. + */ + FILE *ftemp = fopen(filename,"r"); + char s[6]; + int i; + + if (!ftemp) { + return (Pixmap) NULL; + } + if ((long)fread(s,1,6,ftemp) < (long)6) { + fclose(ftemp); + return (Pixmap) NULL; + } + fclose(ftemp); + /* check s for XPM string */ + isxbm = 1; /* default to xbm */ + for (i = 0; i <= 3; i++) + if (!strncmp(&s[i], "XPM", 3)) + isxbm = 0; + } + + if (isxbm) { /* isxbm = 1 => .xbm file */ + if (XReadBitmapFile(stddpy, DefaultRootWindow(stddpy), filename, + width, height, &p1, &xhot, &yhot) != BitmapSuccess) + return (Pixmap) NULL; + else *status = 0; + p2 = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), *width, *height, + DefaultDepth(stddpy,DefaultScreen(stddpy))); + } + else { /* isxbm == 0 => .xpm file */ +#ifndef HaveXpmFormat + return NULL; +#else /* HaveXpmFormat */ + XpmAttributes a; + XColor color; + LinearColor clr; + Pixmap dummy; + a.npixels = 0; + a.colormap = wd->cmap; + a.valuemask = XpmReturnPixels | XpmColormap; + + *status = XpmReadFileToPixmap(stddpy, DefaultRootWindow(stddpy), + filename, &p2, &dummy, &a); + + if (*status == XpmColorFailed && go_virtual(w)) { + /* try again with a virtual colormap */ + a.npixels = 0; + a.colormap = wd->cmap; + a.valuemask = XpmReturnPixels | XpmColormap; + *status = XpmReadFileToPixmap(stddpy, DefaultRootWindow(stddpy), + filename, &p2, &dummy, &a); + } + + if (*status != XpmSuccess) { + if (*status == XpmColorFailed) + *status = 1; + else + return (Pixmap) NULL; + } + else *status = 0; + *height = a.height; + *width = a.width; + + /* + * if the loaded image is to cover an entire window, free up colors + * currently in use by the window + */ + if (atorigin && *width >= ws->pixwidth && *height >= ws->pixheight + && wc->clipw < 0) + free_xcolors(w, 0); + + /* + * OK, now register all the allocated colors with the display + * and window in which we are residing. + */ + for (i = 0; i < a.npixels; i++) { + j = alc_centry(wd); + if (j == 0) + return (Pixmap) NULL; + /* + * Store their allocated pixel (r,g,b) values. + */ + color.pixel = wd->colrptrs[j]->c = a.pixels[i]; + XQueryColor(stddpy, wd->cmap, &color); + wd->colrptrs[j]->r = color.red; + wd->colrptrs[j]->g = color.green; + wd->colrptrs[j]->b = color.blue; + clr = lcolor(w, color); + sprintf(wd->colrptrs[j]->name, "%ld,%ld,%ld", + clr.red, clr.green, clr.blue); + if (ws->numColors <= WMAXCOLORS) { + if (ws->theColors == NULL) { + ws->theColors = (short *)calloc(WMAXCOLORS, sizeof(short)); + if (ws->theColors == NULL) + return (Pixmap) NULL; + } + ws->theColors[ws->numColors++] = j; + } + } +#endif /* HaveXpmFormat */ + } + + if (p2 == (Pixmap) NULL) { + return (Pixmap) NULL; + } + + if (stdgc == NULL) { + gcv.foreground = wc->fg->c; + gcv.background = wc->bg->c; + gcv.font = wc->font->fsp->fid; + wc->gc = XCreateGC(stddpy, p2, gcmask, &gcv); + stdgc = wc->gc; + } + + if (isxbm) { + XCopyPlane(stddpy, p1, p2, stdgc, 0, 0, *width, *height, 0, 0, 1); + XSync(stddpy, False); + XFreePixmap(stddpy, p1); + } + return p2; + } + +/* + * Interpret a platform-specific color name s. + * Under X, we can do this only if there is a window. + */ +int nativecolor(w, s, r, g, b) +wbp w; +char *s; +long *r, *g, *b; + { + XColor colorcell; + LinearColor clr; + wsp ws; + wdp wd; + + if (!w) /* if no window, give up */ + return 0; + ws = w->window; + wd = ws->display; + if (!XParseColor(wd->display, wd->cmap, s, &colorcell)) + return 0; /* if unknown to X */ + clr = lcolor(w, colorcell); + *r = clr.red; + *g = clr.green; + *b = clr.blue; + return 1; + } + +/* + * Convert an X color into an Icon linear color. + */ +LinearColor lcolor(w, colorcell) +wbp w; +XColor colorcell; + { + LinearColor l; + double gamma = w->context->gamma; + + l.red = 65535 * pow((int)colorcell.red / 65535.0, gamma); + l.green = 65535 * pow((int)colorcell.green / 65535.0, gamma); + l.blue = 65535 * pow((int)colorcell.blue / 65535.0, gamma); + return l; + } + +/* + * Convert an Icon linear color into an X colorcell. + */ +XColor xcolor(w, c) +wbp w; +LinearColor c; + { + XColor x; + double invgamma = 1.0 / w->context->gamma; + + x.red = 65535 * pow(c.red / 65535.0, invgamma); + x.green = 65535 * pow(c.green / 65535.0, invgamma); + x.blue = 65535 * pow(c.blue / 65535.0, invgamma); + x.flags = DoRed | DoGreen | DoBlue; + return x; + } + + +int raiseWindow(w) +wbp w; + { + wsp ws = w->window; + if (ws->win) { + XRaiseWindow(ws->display->display, ws->win); + XSetInputFocus(ws->display->display,ws->win,RevertToParent,CurrentTime); + } + return Succeeded; + } + +int lowerWindow(w) +wbp w; + { + if (w->window->win) + XLowerWindow(w->window->display->display, w->window->win); + return Succeeded; + } + +int walert(w, volume) +wbp w; +int volume; +{ + STDLOCALS(w); + XBell(stddpy, volume); + XFlush(stddpy); + return Succeeded; + } + +#endif /* Graphics */ |