summaryrefslogtreecommitdiff
path: root/src/runtime/rxwin.ri
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/rxwin.ri')
-rw-r--r--src/runtime/rxwin.ri3475
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 */