/* * File: rxrsc.ri - X Window specific resource allocation/deallocation * * Resources are allocated through a layer of internal management * routines in order to handle aliasing and resource sharing. */ static int rgbhash[5000]; /* rgb hash table */ wdp wdsplys; wfp findfont(wbp w, char *fam, int size, int flags); int okfont(char *spec, int size, int flags); int fontcmp(char *font1, char *font2, int size, int flags); /* check for color match */ #define CMATCH(cp, rr, gg, bb) \ ((cp)->r == (rr) && (cp)->g == (gg) && (cp->b) == (bb) && \ (cp)->type == SHARED && (cp)->refcount > 0) /* * Allocate a color given linear r, g, b. Colors are shared on a * per-display basis, but they are often freed on a per-window basis, * so they are remembered in two structures. */ wclrp alc_rgb(w,s,r,g,b,is_iconcolor) wbp w; char *s; unsigned int r,g,b; int is_iconcolor; { wclrp cp; LinearColor lc; XColor color; int h, i; int *numColors; short *theColors; STDLOCALS(w); /* * handle black and white specially (no allocation) */ if ((r == 0) && (g == 0) && (b == 0)) return wd->colrptrs[0]; if ((r == 65535) && (g == 65535) && (b == 65535)) return wd->colrptrs[1]; if (is_iconcolor) { if (ws->iconColors == NULL) { ws->iconColors = (short *)calloc(WMAXCOLORS, sizeof(short)); if (ws->iconColors == NULL) return NULL; } numColors = &(ws->numiColors); theColors = ws->iconColors; } else { if (ws->theColors == NULL) { ws->theColors = (short *)calloc(WMAXCOLORS, sizeof(short)); if (ws->theColors == NULL) return NULL; } numColors = &(ws->numColors); theColors = ws->theColors; } /* * Change into server-dependent R G B */ lc.red = r; lc.green = g; lc.blue = b; color = xcolor(w, lc); r = color.red; g = color.green; b = color.blue; h = (503 * r + 509 * g + 499 * b) % ElemCount(rgbhash); /* * Search for the color in w's display */ if (wd->visual->class == TrueColor) { /* * TrueColor entries are linked on hash chains. */ i = rgbhash[h]; while (i != 0 && !CMATCH(wd->colrptrs[i],r,g,b)) i = wd->colrptrs[i]->next; if (i == 0) i = wd->numColors; /* indicate not found */ } else { /* * Search linearly through the list of colors. */ for (i = 2; i < wd->numColors; i++) if (CMATCH(wd->colrptrs[i],r,g,b)) break; } if (i >= wd->numColors) { int j; /* * color not found, must allocate */ if (!XAllocColor(stddpy, wd->cmap, &color)) { /* try again with a virtual colormap (but not for an icon) */ if (is_iconcolor || !go_virtual(w) || !XAllocColor(stddpy, wd->cmap, &color)) return NULL; } j = alc_centry(wd); if (j == 0) return NULL; cp = wd->colrptrs[j]; cp->next = rgbhash[h]; rgbhash[h] = j; strcpy(cp->name, s); /* * Store server color as requested in color table. */ cp->r = r; cp->g = g; cp->b = b; cp->c = color.pixel; cp->type = SHARED; /* * Remember in window color list, too, if not TrueColor visual. */ if (wd->visual->class != TrueColor && *numColors < WMAXCOLORS) theColors[(*numColors)++] = j; return cp; } else { /* color is found, alias it and put it in the window color table */ int k; for(k=0; k < *numColors; k++){ if (theColors[k] == i) { /* already there, no further action needed */ return wd->colrptrs[i]; } } wd->colrptrs[i]->refcount++; /* * Remember in window color list, too, if not TrueColor visual. */ if (wd->visual->class != TrueColor && *numColors < WMAXCOLORS) theColors[(*numColors)++] = i; return wd->colrptrs[i]; } } /* * allocate a color entry, return index */ int alc_centry(wd) wdp wd; { int j; if (wd->visual->class == TrueColor) { /* * TrueColor entries are never freed, so skip the search. */ j = wd->numColors; } else { /* * Look for allocated but unused entry (beyond reserved entries 0 and 1) */ for (j = 2; j < wd->numColors; j++) { if (wd->colrptrs[j]->refcount == 0) { wd->colrptrs[j]->refcount = 1; return j; } } } /* * No unused entry found. Make sure there's room for another pointer. */ if (wd->numColors == wd->cpSize) { j = 2 * wd->cpSize; /* double the array size */ wd->colrptrs = realloc(wd->colrptrs, j * sizeof(struct wcolor *)); if (wd->colrptrs == NULL) ReturnErrNum(305, 0); wd->cpSize = j; } /* * Now allocate a new entry. */ j = wd->numColors; wd->colrptrs[j] = calloc(1, sizeof(struct wcolor)); if (wd->colrptrs[j] == NULL) ReturnErrNum(305, 0); wd->colrptrs[j]->refcount = 1; wd->numColors++; return j; } /* * allocate by named color and return Icon color pointer. * This is used by setfg and setbg. */ wclrp alc_color(w,s) wbp w; char *s; { wclrp rv; long r, g, b; /* * convert color to an r,g,b triple */ if (parsecolor(w, s, &r, &g, &b) != Succeeded) return 0; /* * return Icon color structure, allocated & reference counted in display */ Protect(rv = alc_rgb(w, s, r, g, b, 0), return 0); return rv; } /* * copy color entries to reflect pixel transmission via CopyArea() * (assumes w1 and w2 are on the same display) */ void copy_colors(w1, w2) wbp w1, w2; { wsp ws1 = w1->window, ws2 = w2 -> window; wdp wd = ws1->display; int i1, i2, j; for (i1 = 0; i1 < ws1->numColors; i1++) { j = ws1->theColors[i1]; if (wd->colrptrs[j]->refcount > 0 && wd->colrptrs[j]->type != MUTABLE) { for (i2 = 0; i2 < ws2->numColors; i2++) { if (j == ws2->theColors[i2]) break; } if (i2 >= ws2->numColors) { /* need to add this color */ wd->colrptrs[j]->refcount++; if (ws2->display->visual->class != TrueColor && ws2->numColors < WMAXCOLORS) { if (ws2->theColors == NULL) ws2->theColors = (short *)calloc(WMAXCOLORS, sizeof(short)); if (ws2->theColors == NULL) break; /* unlikely bug; should fail or something */ ws2->theColors[ws2->numColors++] = j; } /* else cannot record it -- table full, or unneeded for TrueColor */ } } } } /* * free a single color allocated by a given window */ void free_xcolor(w,c) wbp w; unsigned long c; { int i; STDLOCALS(w); for (i = 0; i < ws->numColors; i++) { if (wd->colrptrs[ws->theColors[i]]->c == c) break; } if (i >= ws->numColors) { /* "free_xcolor couldn't find the color in the window\n" */ /* (for TrueColor visuals, this is normal) */ } else { if (--(wd->colrptrs[ws->theColors[i]]->refcount) == 0) { XFreeColors(stddpy, wd->cmap, &c, 1, 0); ws->numColors--; if (ws->numColors != i) ws->theColors[i] = ws->theColors[ws->numColors]; } } } /* * free the colors allocated by a given window. extent indicates how much * to free. extent == 0 implies window colors except black, white, * fg, bg, wbg, and mutable colors. extent == 1 implies free icon colors. * extent == 2 implies free window AND fg/bg/wbg (window is closed) */ void free_xcolors(w, extent) wbp w; int extent; { int i; unsigned long toFree[WMAXCOLORS]; int freed = 0; int *numColors; int numSaved; short *theColors; STDLOCALS(w); numColors = (extent==1 ? &(ws->numiColors) : &(ws->numColors)); theColors = (extent==1 ? ws->iconColors : ws->theColors); numSaved = 0; for (i = *numColors-1; i >= 0; i--) { int j = theColors[i]; if (j < 2) /* black & white are permanent residents */ continue; /* * don't free fg, bg, or mutable color */ if (((extent==0) && (wd->colrptrs[j] == w->context->fg)) || ((extent==0) && (wd->colrptrs[j] == w->context->bg)) || (wd->colrptrs[j]->type == MUTABLE)) { theColors[numSaved++] = j; continue; } #ifdef FreeColorFix /* * don't free ANY context's fg or bg */ { wcp wc; int numhits = 0; for(wc=wcntxts; wc; wc=wc->next) { if ((wc->fg == wd->colrptrs[j]) || (wc->bg == wd->colrptrs[j])) { if (numhits == 0) theColors[numSaved++] = j; numhits++; } } if (numhits) { if (numhits > wd->colrptrs[j]->refcount) wd->colrptrs[j]->refcount = numhits; continue; } } #endif /* FreeColorFix */ if (--(wd->colrptrs[j]->refcount) == 0) { toFree[freed++] = wd->colrptrs[j]->c; } } if (freed>0) XFreeColors(stddpy, wd->cmap, toFree, freed,0); *numColors = numSaved; } /* * Allocate a virtual colormap with all colors used by the client copied from * the default colormap to new colormap, and set all windows to use this new * colormap. Returns 0 on failure. */ int go_virtual(w) wbp w; { wsp win; STDLOCALS(w); if (wd->cmap != DefaultColormap(stddpy,wd->screen)) return 0; /* already using a virtual colormap */ wd->cmap = XCopyColormapAndFree(stddpy,wd->cmap); /* set the colormap for all the windows to the new colormap */ for (win = wstates; win; win = win->next) if ((win->display->display == stddpy) & (win->win != (Window)NULL)) XSetWindowColormap(stddpy, win->win, wd->cmap); return 1; } /* * allocate a display on machine s */ wdp alc_display(s) char *s; { int i; double g; wdp wd; XColor color; wclrp cp; if (s == NULL) s = getenv("DISPLAY"); if (s == NULL) s = ""; for(wd = wdsplys; wd; wd = wd->next) if (!strcmp(wd->name,s)) { wd->refcount++; return wd; } GRFX_ALLOC(wd, _wdisplay); strcpy(wd->name,s); wd->display = XOpenDisplay((*s=='\0') ? NULL : s); if (wd->display == NULL) { wd->refcount = 0; free(wd); return NULL; } wd->screen = DefaultScreen(wd->display); wd->visual = DefaultVisual(wd->display, wd->screen); wd->cmap = DefaultColormap(wd->display, wd->screen); /* * Allocate initial set of color slots. */ wd->cpSize = 8; /* start with room for 8 colors */ wd->colrptrs = alloc(wd->cpSize * sizeof(struct wcolor *)); if (wd->colrptrs == NULL) ReturnErrNum(305, NULL); /* * Color slots 0 and 1 are permanently reserved for black and white * respectively. */ alc_centry(wd); /* allocate slot 0 (ambiguous return value) */ if (!alc_centry(wd)) /* allocate slot 1 */ ReturnErrNum(305, NULL); cp = wd->colrptrs[0]; strcpy(cp->name,"black"); cp->type = SHARED; cp->r = cp->g = cp->b = 0; color.red = color.green = color.blue = 0; if (XAllocColor(wd->display, wd->cmap, &color)) cp->c = color.pixel; else cp->c = BlackPixel(wd->display,wd->screen); cp = wd->colrptrs[1]; strcpy(cp->name,"white"); cp->type = SHARED; cp->r = cp->g = cp->b = 65535; color.red = color.green = color.blue = 65535; if (XAllocColor(wd->display, wd->cmap, &color)) cp->c = color.pixel; else cp->c = WhitePixel(wd->display,wd->screen); /* * Set the default gamma correction value for windows that are * opened on this display. Start with configuration default, * but if we can get an interpretation of "RGBi:.5/.5/.5", * calculate a gamma value from that instead. */ wd->gamma = GammaCorrection; if (XParseColor(wd->display, wd->cmap, "RGBi:.5/.5/.5", &color)) { g = .299 * color.red + .587 * color.green + .114 * color.blue; g /= 65535; if (g >= 0.1 && g <= 0.9) /* sanity check */ wd->gamma = log(0.5) / log(g); } /* * Initialize fonts and other things. */ wd->numFonts = 1; wd->fonts = (wfp)malloc(sizeof(struct _wfont)); if (wd->fonts == NULL) { free(wd); return NULL; } wd->fonts->refcount = 1; wd->fonts->next = wd->fonts->previous = NULL; wd->fonts->name = malloc(6); if (wd->fonts->name == NULL) { free(wd); return NULL; } strcpy(wd->fonts->name,"fixed"); wd->fonts->fsp = XLoadQueryFont(wd->display, "fixed"); if (wd->fonts->fsp == NULL) { /* couldn't load "fixed"! */ free(wd); return NULL; } { XGCValues gcv; Display *stddpy = wd->display; gcv.font = wd->fonts->fsp->fid; gcv.foreground = wd->colrptrs[0]->c; gcv.background = wd->colrptrs[1]->c; gcv.fill_style = FillSolid; gcv.cap_style = CapProjecting; wd->icongc = XCreateGC(stddpy, DefaultRootWindow(stddpy), GCFont | GCForeground | GCBackground | GCFillStyle | GCCapStyle, &gcv); if (wd->icongc == NULL) { free(wd); return NULL; } } wd->fonts->height = wd->fonts->fsp->ascent + wd->fonts->fsp->descent; GRFX_LINK(wd, wdsplys); return wd; } /* * allocate font s in the display attached to w */ wfp alc_font(w,s) wbp w; char **s; { int flags, size; wfp rv; char family[MAXFONTWORD+1]; char *stdfam; if (strcmp(*s, "fixed") != 0 && parsefont(*s, family, &flags, &size)) { /* * This is a legal Icon font spec (and it's not an unadorned "fixed"). * Check first for special "standard" family names. */ if (!strcmp(family, "mono")) { stdfam = "lucidatypewriter"; flags |= FONTFLAG_MONO + FONTFLAG_SANS; } else if (!strcmp(family, "typewriter")) { stdfam = "courier"; flags |= FONTFLAG_MONO + FONTFLAG_SERIF; } else if (!strcmp(family, "sans")) { stdfam = "helvetica"; flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SANS; } else if (!strcmp(family, "serif")) { stdfam = "times"; flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SERIF; } else stdfam = NULL; if (stdfam) { /* * Standard name: first try preferred family, then generalize. */ rv = findfont(w, stdfam, size, flags); if (!rv) rv = findfont(w, "*", size, flags); } else { /* * Any other name: must match as specified. */ rv = findfont(w, family, size, flags); } if (rv != NULL) return rv; } /* * Not found as an Icon name; may be an X font name. */ return tryfont(w, *s); } /* * return pointer to field i inside XLFD (X Logical Font Description) s. */ char *xlfd_field(s, i) char *s; int i; { int j = 0; while (j < i) { if (*s == '\0') return ""; /* if no such field */ if (*s++ == '-') j++; } return s; } /* * return size of font, treating a scalable font as having size n */ int xlfd_size(s, n) char *s; int n; { char *f; int z; f = xlfd_field(s, XLFD_Size); if (!*f) return 0; z = atoi(f); if (z != 0) return z; else return n; } /* * Find the best font matching a set of specifications. */ wfp findfont(w, family, size, flags) wbp w; char *family; int size, flags; { char fontspec[MAXFONTWORD+100]; char *p, *weight, *slant, *width, *spacing, **fontlist; int n, champ, challenger, bestsize; /* * Construct a font specification that enforces any stated requirements * of size, weight, slant, set width, or proportionality. */ if (size > 0) bestsize = size; else bestsize = DEFAULTFONTSIZE; if (flags & FONTFLAG_MEDIUM) weight = "medium"; else if ((flags & FONTFLAG_DEMI) && (flags & FONTFLAG_BOLD)) weight = "demibold"; else if (flags & FONTFLAG_BOLD) weight = "bold"; else if (flags & FONTFLAG_DEMI) weight = "demi"; else if (flags & FONTFLAG_LIGHT) weight = "light"; else weight = "*"; if (flags & FONTFLAG_ITALIC) slant = "i"; else if (flags & FONTFLAG_OBLIQUE) slant = "o"; else if (flags & FONTFLAG_ROMAN) slant = "r"; else slant = "*"; if (flags & FONTFLAG_NARROW) width = "narrow"; else if (flags & FONTFLAG_CONDENSED) width = "condensed"; else if (flags & FONTFLAG_NORMAL) width = "normal"; else if (flags & FONTFLAG_WIDE) width = "wide"; else if (flags & FONTFLAG_EXTENDED) width = "extended"; else width = "*"; if (flags & FONTFLAG_PROPORTIONAL) spacing = "p"; else spacing = "*"; /* can't specify {m or c} to X */ sprintf(fontspec, "-*-%s-%s-%s-%s-*-*-*-*-*-%s-*-*-*", family, weight, slant, width, spacing); /* * Get a list of matching fonts from the X server and find the best one. */ fontlist = XListFonts(w->window->display->display, fontspec, 2500, &n); champ = 0; while (champ < n && !okfont(fontlist[champ], size, flags)) champ++; if (champ >= n) { XFreeFontNames(fontlist); return NULL; /* nothing acceptable */ } for (challenger = champ + 1; challenger < n; challenger++) if (okfont(fontlist[challenger], size, flags) && fontcmp(fontlist[challenger], fontlist[champ], bestsize, flags) < 0) champ = challenger; /* * Set the scaling field, if needed, and load the font. */ p = xlfd_field(fontlist[champ], XLFD_Size); if (p[0] == '0' && p[1] == '-') sprintf(fontspec, "%.*s%d%s", p - fontlist[champ], fontlist[champ], bestsize, p + 1); else strcpy(fontspec, fontlist[champ]); XFreeFontNames(fontlist); return tryfont(w, fontspec); } /* * check for minimum acceptability of a font * (things that couldn't be filtered by the XLFD pattern): * -- size wrong (there's a bug in OpenWindows 3.3 else X could do it) * -- not monospaced (can't set pattern to match m or c but not p) */ int okfont(spec, size, flags) char *spec; int size, flags; { if (size > 0 && xlfd_size(spec, size) != size) return 0; /* can't match explicit size request */ if ((flags & FONTFLAG_MONO) && xlfd_field(spec, XLFD_Spacing)[0] == 'p') return 0; /* requested mono, but this isn't */ return 1; } /* * rank two fonts based on whether XLFD field n matches a preferred value. * returns <0 if font1 is better, >0 if font2 is better, else 0. */ int fieldcmp(font1, font2, value, field) char *font1, *font2, *value; int field; { int len, r1, r2; len = strlen(value); r1 = (strncmp(xlfd_field(font1, field), value, len) == 0); r2 = (strncmp(xlfd_field(font2, field), value, len) == 0); return r2 - r1; /* -1, 0, or 1 */ } /* * rank two fonts. * returns <0 if font1 is better, >0 if font2 is better, else 0. * * Note that explicit requests for size, slant, weight, and width caused * earlier filtering in findfont(), so all those flags aren't checked * again here; normal values are just favored in case nothing was specified. */ int fontcmp(font1, font2, size, flags) char *font1, *font2; int size, flags; { int n; /* return if exactly one of the fonts matches value s in field n */ #define PREFER(s,n) \ do { int r = fieldcmp(font1, font2, s, n); if (r != 0) return r; } while (0) /* return if exactly one of the fonts does NOT match value s in field n */ #define SPURN(s,n) \ do { int r = fieldcmp(font1, font2, s, n); if (r != 0) return -r; } while (0) /* * Prefer the font that is closest to the desired size. */ n = abs(size - xlfd_size(font1, size)) - abs(size - xlfd_size(font2, size)); if (n != 0) return n; /* * try to check serifs (though not always indicated in X font description) */ if (flags & FONTFLAG_SANS) { PREFER("sans", XLFD_AddStyle); SPURN("serif", XLFD_AddStyle); } else if (flags & FONTFLAG_SERIF) { PREFER("serif", XLFD_AddStyle); SPURN("sans", XLFD_AddStyle); } /* * prefer normal values for other fields. These only have an effect * for fields that were wildcarded when requesting the font list. */ PREFER("r", XLFD_Slant); /* prefer roman slant */ PREFER("medium", XLFD_Weight); /* prefer medium weight */ SPURN("demi", XLFD_Weight); /* prefer non-demi if no medium */ PREFER("normal", XLFD_SetWidth); /* prefer normal width */ PREFER("iso8859", XLFD_CharSet); /* prefer font of ASCII chars */ SPURN("0", XLFD_PointSize); /* prefer tuned font to scaled */ PREFER("adobe", XLFD_Foundry); /* these look better than others */ /* no significant difference */ return 0; } /* * load a font and return a font structure. */ wfp tryfont(w,s) wbp w; char *s; { wdp wd = w->window->display; wfp rv; /* * see if the font is already loaded on this display */ for(rv = wd->fonts; rv != NULL; rv = rv->next) { if (!strcmp(s,rv->name)) break; } if (rv != NULL) { rv->refcount++; return rv; } /* * load a new font */ GRFX_ALLOC(rv, _wfont); rv->name = malloc(strlen(s) + 1); if (rv->name == NULL) ReturnErrNum(305, NULL); strcpy(rv->name, s); rv->fsp = XLoadQueryFont(wd->display, rv->name); if (rv->fsp == NULL){ free(rv->name); free(rv); return NULL; } rv->height = rv->fsp->ascent + rv->fsp->descent; w->context->leading = rv->height; /* * link the font into this displays fontlist (but not at the head!) */ rv->next = wd->fonts->next; rv->previous = wd->fonts; if (wd->fonts->next) wd->fonts->next->previous = rv; wd->fonts->next = rv; return rv; } /* * allocate a context. Can't be called until w has a display and window. */ wcp alc_context(w) wbp w; { wcp wc; wdp wd = w->window->display; GRFX_ALLOC(wc, _wcontext); wc->serial = ++context_serial; wc->display = wd; wd->refcount++; wc->fg = wd->colrptrs[0]; wc->fg->refcount++; wc->bg = wd->colrptrs[1]; wc->bg->refcount++; wc->font = wd->fonts; wc->leading = wd->fonts->height; wc->drawop = GXcopy; wc->gamma = wd->gamma; wc->clipx = wc->clipy = 0; wc->clipw = wc->cliph = -1; wc->linewidth = 1; GRFX_LINK(wc, wcntxts); return wc; } /* * allocate a context, cloning attributes from an existing context */ wcp clone_context(w) wbp w; { wcp wc, rv; XGCValues gcv; XRectangle rec; unsigned long gcmask = GCFont | GCForeground | GCBackground | GCFillStyle | GCCapStyle | GCLineWidth | GCLineStyle; wc = w->context; Protect(rv = alc_context(w), return NULL); rv->dx = wc->dx; rv->dy = wc->dy; rv->clipx = wc->clipx; rv->clipy = wc->clipy; rv->clipw = wc->clipw; rv->cliph = wc->cliph; rv->fg = wc->fg; rv->fg->refcount++; rv->bg = wc->bg; rv->bg->refcount++; rv->font = wc->font; rv->font->refcount++; rv->fillstyle = wc->fillstyle; rv->linestyle = wc->linestyle; rv->linewidth = wc->linewidth; rv->drawop = wc->drawop; rv->gamma = wc->gamma; rv->bits = wc->bits; if (ISXORREVERSE(w)) gcv.foreground = rv->fg->c ^ rv->bg->c; else gcv.foreground = rv->fg->c; gcv.background = rv->bg->c; gcv.font = rv->font->fsp->fid; gcv.line_style = rv->linestyle; gcv.line_width = rv->linewidth; if (rv->linewidth > 1) { gcv.dashes = 3 * rv->linewidth; gcmask |= GCDashList; } gcv.fill_style = rv->fillstyle; gcv.cap_style = CapProjecting; rv->gc = XCreateGC(w->window->display->display,w->window->pix,gcmask,&gcv); if (rv->gc == NULL) { free(rv); return NULL; } if (rv->clipw >= 0) { rec.x = rv->clipx; rec.y = rv->clipy; rec.width = rv->clipw; rec.height = rv->cliph; XSetClipRectangles(rv->display->display, rv->gc, 0, 0, &rec, 1,Unsorted); } return rv; } /* * allocate a window state structure */ wsp alc_winstate() { wsp ws; GRFX_ALLOC(ws, _wstate); ws->serial = ++canvas_serial; ws->bits = 1024; /* echo ON; others OFF */ ws->filep = nulldesc; ws->listp = nulldesc; ws->theCursor = si_s2i(cursorsyms, "left ptr") >> 1; ws->iconic = NormalState; ws->posx = ws->posy = -(MaxInt); GRFX_LINK(ws, wstates); return ws; } /* * free a window state */ int free_window(ws) wsp ws; { ws->refcount--; if(ws->refcount == 0) { ws->bits |= 1; /* SETZOMBIE */ if (ws->win != (Window) NULL) { XDestroyWindow(ws->display->display, ws->win); XFlush(ws->display->display); while (ws->win != (Window) NULL) if (pollevent() == -1) return -1; } GRFX_UNLINK(ws, wstates); } return 0; } /* * free a window context */ void free_context(wc) wcp wc; { wc->refcount--; if(wc->refcount == 0) { if (wc->gc != NULL) XFreeGC(wc->display->display, wc->gc); free_display(wc->display); GRFX_UNLINK(wc, wcntxts); } } /* * free a display */ void free_display(wd) wdp wd; { wd->refcount--; if(wd->refcount == 0) { if (wd->cmap != DefaultColormap(wd->display, wd->screen)) XFreeColormap(wd->display, wd->cmap); XCloseDisplay(wd->display); if (wd->previous) wd->previous->next = wd->next; else wdsplys = wd->next; if (wd->next) wd->next->previous = wd->previous; free(wd); } }