home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / runtime / rxrsc.ri < prev    next >
Text File  |  1996-03-22  |  23KB  |  915 lines

  1. /*
  2.  * File: rxrsc.ri - X Window specific resource allocation/deallocation
  3.  *
  4.  * Resources are allocated through a layer of internal management
  5.  * routines in order to handle aliasing and resource sharing.
  6.  */
  7.  
  8. wdp wdsplys;
  9.  
  10. wfp    findfont    Params((wbp w, char *fam, int size, int flags));
  11.  
  12.  
  13. /*
  14.  * Allocate a color given linear r, g, b. Colors are shared on a
  15.  * per-display basis, but they are often freed on a per-window basis,
  16.  * so they are remembered in two structures.
  17.  */
  18. wclrp alc_rgb(w,s,r,g,b,is_iconcolor)
  19. wbp w;
  20. char *s;
  21. unsigned int r,g,b;
  22. int is_iconcolor;
  23.    {
  24.    LinearColor lc;
  25.    XColor color;
  26.    int i;
  27.    int *numColors;
  28.    short *theColors;
  29.    STDLOCALS(w);
  30.  
  31.    /*
  32.     * handle black and white specially (no allocation)
  33.     */
  34.    if ((r == 0) && (g == 0) && (b == 0))
  35.       return &(wd->colors[0]);
  36.    if ((r == 65535) && (g == 65535) && (b == 65535))
  37.       return &(wd->colors[1]);
  38.  
  39.    if (is_iconcolor) {
  40.       if (ws->iconColors == NULL) {
  41.      ws->iconColors = (short *)calloc(WMAXCOLORS, sizeof(short));
  42.      if (ws->iconColors == NULL) return NULL;
  43.      }
  44.       numColors = &(ws->numiColors);
  45.       theColors = ws->iconColors;
  46.       }
  47.    else {
  48.       if (ws->theColors == NULL) {
  49.      ws->theColors = (short *)calloc(WMAXCOLORS, sizeof(short));
  50.      if (ws->theColors == NULL) return NULL;
  51.      }
  52.       numColors = &(ws->numColors);
  53.       theColors = ws->theColors;
  54.       }
  55.  
  56.    /*
  57.     * Change into server-dependent R G B
  58.     */
  59.    lc.red = r;
  60.    lc.green = g;
  61.    lc.blue = b;
  62.    color = xcolor(w, lc);
  63.    r = color.red;
  64.    g = color.green;
  65.    b = color.blue;
  66.  
  67.    /*
  68.     * Search for the color in w's display
  69.     */
  70.    for (i = 2; i < wd->numColors; i++) {
  71.       if (wd->colors[i].refcount>0 &&
  72.       wd->colors[i].type == SHARED &&
  73.           color.red == wd->colors[i].r &&
  74.           color.green == wd->colors[i].g &&
  75.           color.blue == wd->colors[i].b)
  76.          break;
  77.       }
  78.  
  79.    if (i >= wd->numColors) {
  80.       int j;
  81.       /*
  82.        * color not found, must allocate
  83.        * first verify there is room in window color table.
  84.        */
  85.       if (*numColors == WMAXCOLORS) {
  86.      return NULL;
  87.          }
  88.  
  89.       if (!XAllocColor(stddpy, wd->cmap, &color)) {
  90.      /* try again with a virtual colormap (but not for an icon) */
  91.      if (is_iconcolor || !go_virtual(w) ||
  92.          !XAllocColor(stddpy, wd->cmap, &color))
  93.             return NULL;
  94.          }
  95.  
  96.       j = alc_centry(wd);
  97.       if (j == 0)
  98.          return NULL;
  99.       strcpy(wd->colors[j].name, s);
  100.       /*
  101.        * Store server color as requested in color table.
  102.        */
  103.       wd->colors[j].r = r;
  104.       wd->colors[j].g = g;
  105.       wd->colors[j].b = b;
  106.       wd->colors[j].c = color.pixel;
  107.       wd->colors[j].type = SHARED;
  108.       theColors[(*numColors)++] = j;
  109.       return &(wd->colors[j]);
  110.       }
  111.    else {
  112.       /* color is found, alias it and put it in the window color table */
  113.       int k;
  114.       for(k=0; k < *numColors; k++){
  115.          if (theColors[k] == i) {
  116.         /* already there, no further action needed */
  117.         return &(wd->colors[i]);
  118.             }
  119.          }
  120.       wd->colors[i].refcount++;
  121.       theColors[(*numColors)++] = i;
  122.       return &(wd->colors[i]);
  123.       }
  124.    }
  125.  
  126. /*
  127.  * allocate a color entry, return index (or 0 if table is full)
  128.  */
  129. int alc_centry(wd)
  130. wdp wd;
  131. {
  132.    int j;
  133.  
  134.    for (j = 2; j < DMAXCOLORS; j++)
  135.       if (wd->colors[j].refcount == 0)
  136.      break;
  137.    if (j == DMAXCOLORS)
  138.       return 0;
  139.    if (j == wd->numColors)
  140.       wd->numColors++;
  141.    else if (j > wd->numColors)
  142.       return 0;        /* internal confusion */
  143.  
  144.    wd->colors[j].refcount = 1;
  145.    return j;
  146. }
  147.  
  148. /*
  149.  * allocate by named color and return Icon color pointer.
  150.  *  This is used by setfg and setbg.
  151.  */
  152. wclrp alc_color(w,s)
  153. wbp w;
  154. char *s;
  155.    {
  156.    wclrp rv;
  157.    wsp ws = w->window;
  158.    long r, g, b;
  159.  
  160.    /*
  161.     * convert color to an r,g,b triple
  162.     */
  163.    if (parsecolor(w, s, &r, &g, &b) != Succeeded)
  164.       return 0;
  165.  
  166.    /*
  167.     * return Icon color structure, allocated & reference counted in display
  168.     */
  169.    Protect(rv = alc_rgb(w, s, r, g, b, 0), return 0);
  170.    return rv;
  171.    }
  172.  
  173. /*
  174.  * copy color entries to reflect pixel transmission via CopyArea()
  175.  * (assumes w1 and w2 are on the same display)
  176.  */
  177. novalue copy_colors(w1, w2)
  178. wbp w1, w2;
  179.    {
  180.    wsp ws1 = w1->window, ws2 = w2 -> window;
  181.    wdp wd = ws1->display;
  182.    int i1, i2, j;
  183.  
  184.    for (i1 = 0; i1 < ws1->numColors; i1++) {
  185.       j = ws1->theColors[i1];
  186.       if (wd->colors[j].refcount > 0 && wd->colors[j].type != MUTABLE) {
  187.      for (i2 = 0; i2 < ws2->numColors; i2++) {
  188.         if (j == ws2->theColors[i2])
  189.            break;
  190.         }
  191.      if (i2 >= ws2->numColors) {
  192.         /* need to add this color */
  193.         wd->colors[j].refcount++;
  194.         if (ws2->numColors < WMAXCOLORS) {
  195.            if (ws2->theColors == NULL)
  196.           ws2->theColors = (short *)calloc(WMAXCOLORS, sizeof(short));
  197.            if (ws2->theColors == NULL)
  198.           break; /* unlikely bug; should fail or something */
  199.            ws2->theColors[ws2->numColors++] = j;
  200.            }
  201.         /* else cannot record it -- table full */
  202.         }
  203.      }
  204.       }
  205.    }
  206.  
  207. /*
  208.  * free a single color allocated by a given window
  209.  */
  210. novalue free_xcolor(w,c)
  211. wbp w;
  212. unsigned long c;
  213.    {
  214.    int i;
  215.    STDLOCALS(w);
  216.  
  217.    for (i = 0; i < ws->numColors; i++) {
  218.       if (wd->colors[ws->theColors[i]].c == c) break;
  219.       }
  220.    if (i >= ws->numColors) {
  221.       /* "free_xcolor couldn't find the color in the window\n" */
  222.       }
  223.    else {
  224.       if (--(wd->colors[ws->theColors[i]].refcount) == 0) {
  225.      XFreeColors(stddpy, wd->cmap, &c, 1, 0);
  226.      ws->numColors--;
  227.      if (ws->numColors != i)
  228.         ws->theColors[i] = ws->theColors[ws->numColors];
  229.          }
  230.       }
  231.    }
  232.  
  233. /*
  234.  * free the colors allocated by a given window.  extent indicates how much
  235.  * to free.  extent == 0 implies window colors except black, white,
  236.  * fg, bg, wbg, and mutable colors.  extent == 1 implies free icon colors.
  237.  * extent == 2 implies free window AND fg/bg/wbg (window is closed)
  238.  */
  239. novalue free_xcolors(w, extent)
  240. wbp w;
  241. int extent;
  242.    {
  243.    int i;
  244.    unsigned long toFree[DMAXCOLORS];
  245.    int freed = 0;
  246.    int *numColors;
  247.    int numSaved;
  248.    short *theColors;
  249.    STDLOCALS(w);
  250.  
  251.    numColors = (extent==1 ? &(ws->numiColors) : &(ws->numColors));
  252.    theColors = (extent==1 ? ws->iconColors : ws->theColors);
  253.  
  254.    numSaved = 0;
  255.    for (i = *numColors-1; i >= 0; i--) {
  256.       int j = theColors[i];
  257.  
  258.  
  259.       if (j < 2)        /* black & white are permanent residents */
  260.      continue;
  261.       /*
  262.        * don't free fg, bg, or mutable color
  263.        */
  264.       if (((extent==0) && (&(wd->colors[j]) == w->context->fg)) ||
  265.       ((extent==0) && (&(wd->colors[j]) == w->context->bg)) ||
  266.       (wd->colors[j].type == MUTABLE)) {
  267.          theColors[numSaved++] = j;
  268.          continue;
  269.          }
  270.  
  271.       if (--(wd->colors[j].refcount) == 0) {
  272.      toFree[freed++] = wd->colors[j].c;
  273.          }
  274.       }
  275.    if (freed>0)
  276.       XFreeColors(stddpy, wd->cmap, toFree, freed,0);
  277.    *numColors = numSaved;
  278.    }
  279.  
  280. /*
  281.  * Allocate a virtual colormap with all colors used by the client copied from
  282.  * the default colormap to new colormap, and set all windows to use this new
  283.  * colormap.  Returns 0 on failure.
  284.  */
  285. int go_virtual(w)
  286. wbp w;
  287. {
  288.    wsp win;
  289.    STDLOCALS(w);
  290.  
  291.    if (wd->cmap != DefaultColormap(stddpy,wd->screen))
  292.       return 0;    /* already using a virtual colormap */
  293.  
  294.    wd->cmap = XCopyColormapAndFree(stddpy,wd->cmap);
  295.  
  296.    /* set the colormap for all the windows to the new colormap */
  297.  
  298.    for (win = wstates; win; win = win->next)
  299.       if ((win->display->display == stddpy) & (win->win != (Window)NULL))
  300.          XSetWindowColormap(stddpy, win->win, wd->cmap);
  301.  
  302.    return 1;
  303. }
  304.  
  305. /*
  306.  * allocate a display on machine s
  307.  */
  308. wdp alc_display(s)
  309. char *s;
  310.    {
  311.    int i;
  312.    double g;
  313.    wdp wd;
  314.    XColor color;
  315.  
  316.    if (s == NULL) s = getenv("DISPLAY");
  317.    if (s == NULL) s = "";
  318.    for(wd = wdsplys; wd; wd = wd->next)
  319.       if (!strcmp(wd->name,s)) {
  320.          wd->refcount++;
  321.      return wd;
  322.          }
  323.  
  324.    GRFX_ALLOC(wd, _wdisplay);
  325.  
  326.    strcpy(wd->name,s);
  327.    wd->display = XOpenDisplay((*s=='\0') ? NULL : s);
  328.  
  329.    if (wd->display == NULL) {
  330.       wd->refcount = 0;
  331.       free(wd);
  332.       return NULL;
  333.       }
  334.    wd->screen = DefaultScreen(wd->display);
  335.    wd->cmap = DefaultColormap(wd->display, wd->screen);
  336.  
  337.    /*
  338.     * Color slots 0 and 1 are permanently reserved for black and white
  339.     * respectively.  Allocate them explicitly so that they're preserved
  340.     * if we later switch to a virtual colormap.
  341.     */
  342.    strcpy(wd->colors[0].name,"black");
  343.    wd->colors[0].refcount = 1;
  344.    wd->colors[0].type = SHARED;
  345.    wd->colors[0].r = wd->colors[0].g = wd->colors[0].b = 0;
  346.    color.red = color.green = color.blue = 0;
  347.    if (XAllocColor(wd->display, wd->cmap, &color))
  348.       wd->colors[0].c = color.pixel;
  349.    else
  350.       wd->colors[0].c = BlackPixel(wd->display,wd->screen);
  351.  
  352.    strcpy(wd->colors[1].name,"white");
  353.    wd->colors[1].refcount = 1;
  354.    wd->colors[1].type = SHARED;
  355.    wd->colors[1].r = wd->colors[1].g = wd->colors[1].b = 65535;
  356.    color.red = color.green = color.blue = 65535;
  357.    if (XAllocColor(wd->display, wd->cmap, &color))
  358.       wd->colors[1].c = color.pixel;
  359.    else
  360.       wd->colors[1].c = WhitePixel(wd->display,wd->screen);
  361.  
  362.    wd->numColors = 2;
  363.    for (i=2; i < DMAXCOLORS; i++) wd->colors[i].refcount = 0;
  364.  
  365.    /*
  366.     * Set the default gamma correction value for windows that are
  367.     * opened on this display.  Start with configuration default,
  368.     * but if we can get an interpretation of "RGBi:.5/.5/.5",
  369.     * calculate a gamma value from that instead.
  370.     */
  371.    wd->gamma = GammaCorrection;
  372.    if (XParseColor(wd->display, wd->cmap, "RGBi:.5/.5/.5", &color)) {
  373.       g = .299 * color.red + .587 * color.green + .114 * color.blue;
  374.       g /= 65535;
  375.       if (g >= 0.1 && g <= 0.9)        /* sanity check */
  376.          wd->gamma = log(0.5) / log(g);
  377.       }
  378.  
  379.    /*
  380.     * Initialize fonts and other things.
  381.     */
  382.    wd->numFonts = 1;
  383.    wd->fonts = (wfp)malloc(sizeof(struct _wfont));
  384.    if (wd->fonts == NULL) {
  385.       free(wd);
  386.       return NULL;
  387.       }
  388.    wd->fonts->refcount = 1;
  389.    wd->fonts->next = wd->fonts->previous = NULL;
  390.    wd->fonts->name = malloc(6);
  391.    if (wd->fonts->name == NULL) {
  392.       free(wd);
  393.       return NULL;
  394.       }
  395.    strcpy(wd->fonts->name,"fixed");
  396.    wd->fonts->fsp = XLoadQueryFont(wd->display, "fixed");
  397.    if (wd->fonts->fsp == NULL) { /* couldn't load "fixed"! */
  398.       free(wd);
  399.       return NULL;
  400.       }
  401.  
  402.    {
  403.    XGCValues gcv;
  404.    Display *stddpy = wd->display;
  405.    gcv.font = wd->fonts->fsp->fid;
  406.    gcv.foreground = wd->colors[0].c;
  407.    gcv.background = wd->colors[1].c;
  408.    gcv.fill_style = FillSolid;
  409.    gcv.cap_style = CapProjecting;
  410.    wd->icongc = XCreateGC(stddpy, DefaultRootWindow(stddpy),
  411.       GCFont | GCForeground | GCBackground | GCFillStyle | GCCapStyle, &gcv);
  412.    if (wd->icongc == NULL) {
  413.       free(wd);
  414.       return NULL;
  415.       }
  416.    }
  417.  
  418.    wd->fonts->height = wd->fonts->fsp->ascent + wd->fonts->fsp->descent;
  419.  
  420.    GRFX_LINK(wd, wdsplys);
  421.    return wd;
  422.    }
  423.  
  424. /*
  425.  * allocate font s in the display attached to w
  426.  */
  427. wfp alc_font(w,s)
  428. wbp w;
  429. char **s;
  430.    {
  431.    int i, j, k, n, pass, flags, size;
  432.    wfp rv;
  433.    char family[MAXFONTWORD+1];
  434.    char sizestr[8];
  435.    char *stdfam;
  436.  
  437.    if (strcmp(*s, "fixed") != 0 && parsefont(*s, family, &flags, &size)) {
  438.       /*
  439.        * This is a legal Icon font spec (and it's not an unadorned "fixed").
  440.        * Check first for special "standard" family names.
  441.        */
  442.       if (!strcmp(family, "mono")) {
  443.          stdfam = "lucidatypewriter";
  444.          flags |= FONTFLAG_MONO + FONTFLAG_SANS;
  445.          }
  446.       else if (!strcmp(family, "typewriter")) {
  447.          stdfam = "courier";
  448.          flags |= FONTFLAG_MONO + FONTFLAG_SERIF;
  449.          }
  450.       else if (!strcmp(family, "sans")) {
  451.          stdfam = "helvetica";
  452.          flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SANS;
  453.          }
  454.       else if (!strcmp(family, "serif")) {
  455.          stdfam = "times";
  456.          flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SERIF;
  457.          }
  458.       else stdfam = NULL;
  459.    
  460.       if (stdfam) {
  461.          /*
  462.           * Standard name: first try preferred family, then generalize.
  463.           */
  464.          rv = findfont(w, stdfam, size, flags);
  465.          if (!rv)
  466.             rv = findfont(w, "*", size, flags);
  467.          }
  468.       else {
  469.          /*
  470.           * Any other name: must match as specified.
  471.           */
  472.          rv = findfont(w, family, size, flags);
  473.          }
  474.    
  475.       if (rv != NULL)
  476.          return rv;
  477.       }
  478.  
  479.    /*
  480.     * Not found as an Icon name; may be an X font name.
  481.     */
  482.    return tryfont(w, *s);
  483.    }
  484.  
  485. /*
  486.  * return pointer to field i inside XLFD (X Logical Font Description) s.
  487.  */
  488. char *xlfd_field(s, i)
  489. char *s;
  490. int i;
  491.    {
  492.    int j = 0;
  493.    while (j < i) {
  494.       if (*s == '\0') return "";    /* if no such field */
  495.       if (*s++ == '-') j++;
  496.       }
  497.    return s;
  498.    }
  499.  
  500. /*
  501.  * return size of font, treating a scalable font as having size n
  502.  */
  503. int xlfd_size(s, n)
  504. char *s;
  505. int n;
  506.    {
  507.    char *f;
  508.    int z;
  509.  
  510.    f = xlfd_field(s, XLFD_Size);
  511.    if (!*f)
  512.       return 0;
  513.    z = atoi(f);
  514.    if (z != 0)
  515.       return z;
  516.    else
  517.       return n;
  518.    }
  519.  
  520. /*
  521.  * Find the best font matching a set of specifications.
  522.  */
  523. wfp findfont(w, family, size, flags)
  524. wbp w;
  525. char *family;
  526. int size, flags;
  527.    {
  528.    char fontspec[MAXFONTWORD+100];
  529.    char *p, *weight, *slant, *width, *spacing, **fontlist;
  530.    int n, champ, challenger, bestsize;
  531.  
  532.    /*
  533.     * Construct a font specification that enforces any stated requirements
  534.     * of size, weight, slant, set width, or proportionality.
  535.     */
  536.    if (size > 0)
  537.       bestsize = size;
  538.    else
  539.       bestsize = DEFAULTFONTSIZE;
  540.  
  541.    if (flags & FONTFLAG_MEDIUM)
  542.       weight = "medium";
  543.    else if ((flags & FONTFLAG_DEMI) && (flags & FONTFLAG_BOLD))
  544.       weight = "demibold";
  545.    else if (flags & FONTFLAG_BOLD)
  546.       weight = "bold";
  547.    else if (flags & FONTFLAG_DEMI)
  548.       weight = "demi";
  549.    else if (flags & FONTFLAG_LIGHT)
  550.       weight = "light";
  551.    else
  552.       weight = "*";
  553.  
  554.    if (flags & FONTFLAG_ITALIC)
  555.       slant = "i";
  556.    else if (flags & FONTFLAG_OBLIQUE)
  557.       slant = "o";
  558.    else if (flags & FONTFLAG_ROMAN)
  559.       slant = "r";
  560.    else
  561.       slant = "*";
  562.  
  563.    if (flags & FONTFLAG_NARROW)
  564.       width = "narrow";
  565.    else if (flags & FONTFLAG_CONDENSED)
  566.       width = "condensed";
  567.    else if (flags & FONTFLAG_NORMAL)
  568.       width = "normal";
  569.    else if (flags & FONTFLAG_WIDE)
  570.       width = "wide";
  571.    else if (flags & FONTFLAG_EXTENDED)
  572.       width = "extended";
  573.    else
  574.       width = "*";
  575.  
  576.    if (flags & FONTFLAG_PROPORTIONAL)
  577.       spacing = "p";
  578.    else
  579.       spacing = "*";            /* can't specify {m or c} to X */
  580.  
  581.    sprintf(fontspec, "-*-%s-%s-%s-%s-*-*-*-*-*-%s-*-*-*",
  582.       family, weight, slant, width, spacing);
  583.  
  584.    /*
  585.     * Get a list of matching fonts from the X server and find the best one.
  586.     */
  587.    fontlist = XListFonts(w->window->display->display, fontspec, 2500, &n);
  588.    champ = 0;
  589.    while (champ < n && !okfont(fontlist[champ], size, flags))
  590.       champ++;
  591.    if (champ >= n) {
  592.       XFreeFontNames(fontlist);
  593.       return NULL;            /* nothing acceptable */
  594.       }
  595.    for (challenger = champ + 1; challenger < n; challenger++) 
  596.       if (okfont(fontlist[challenger], size, flags)
  597.       && fontcmp(fontlist[challenger], fontlist[champ], bestsize, flags) < 0)
  598.          champ = challenger;
  599.  
  600.    /*
  601.     * Set the scaling field, if needed, and load the font.
  602.     */
  603.    p = xlfd_field(fontlist[champ], XLFD_Size);
  604.    if (p[0] == '0' && p[1] == '-')
  605.       sprintf(fontspec, "%.*s%d%s", p - fontlist[champ],
  606.          fontlist[champ], bestsize, p + 1);
  607.    else
  608.       strcpy(fontspec, fontlist[champ]);
  609.    XFreeFontNames(fontlist);
  610.    return tryfont(w, fontspec);
  611.    }
  612.  
  613. /*
  614.  * check for minimum acceptability of a font
  615.  * (things that couldn't be filtered by the XLFD pattern):
  616.  * -- size wrong (there's a bug in OpenWindows 3.3 else X could do it)
  617.  * -- not monospaced (can't set pattern to match m or c but not p)
  618.  */
  619. int okfont(spec, size, flags)
  620. char *spec;
  621. int size, flags;
  622.    {
  623.    if (size > 0 && xlfd_size(spec, size) != size)
  624.       return 0;            /* can't match explicit size request */
  625.    if ((flags & FONTFLAG_MONO) && xlfd_field(spec, XLFD_Spacing)[0] == 'p')
  626.       return 0;            /* requested mono, but this isn't */
  627.    return 1;
  628.    }
  629.  
  630. /*
  631.  * rank two fonts based on whether XLFD field n matches a preferred value.
  632.  * returns <0 if font1 is better, >0 if font2 is better, else 0.
  633.  */
  634. int fieldcmp(font1, font2, value, field)
  635. char *font1, *font2, *value;
  636. int field;
  637.    {
  638.    int len, r1, r2;
  639.  
  640.    len = strlen(value);
  641.    r1 = (strncmp(xlfd_field(font1, field), value, len) == 0);
  642.    r2 = (strncmp(xlfd_field(font2, field), value, len) == 0);
  643.    return r2 - r1;            /* -1, 0, or 1 */
  644.    }
  645.  
  646. /*
  647.  * rank two fonts.
  648.  * returns <0 if font1 is better, >0 if font2 is better, else 0.
  649.  *
  650.  * Note that explicit requests for size, slant, weight, and width caused
  651.  * earlier filtering in findfont(), so all those flags aren't checked
  652.  * again here; normal values are just favored in case nothing was specified.
  653.  */
  654. int fontcmp(font1, font2, size, flags)
  655. char *font1, *font2;
  656. int size, flags;
  657.    {
  658.    int n;
  659.  
  660. /* return if exactly one of the fonts matches value s in field n */
  661. #define PREFER(s,n) \
  662. do { int r = fieldcmp(font1, font2, s, n); if (r != 0) return r; } while (0)
  663.  
  664. /* return if exactly one of the fonts does NOT match value s in field n */
  665. #define SPURN(s,n) \
  666. do { int r = fieldcmp(font1, font2, s, n); if (r != 0) return -r; } while (0)
  667.  
  668.    /*
  669.     * Prefer the font that is closest to the desired size.
  670.     */
  671.    n = abs(size - xlfd_size(font1, size)) - abs(size - xlfd_size(font2, size));
  672.    if (n != 0)
  673.       return n;
  674.  
  675.    /*
  676.     * try to check serifs (though not always indicated in X font description)
  677.     */
  678.    if (flags & FONTFLAG_SANS) {
  679.       PREFER("sans", XLFD_AddStyle);
  680.       SPURN("serif", XLFD_AddStyle);
  681.       }
  682.    else if (flags & FONTFLAG_SERIF) {
  683.       PREFER("serif", XLFD_AddStyle);
  684.       SPURN("sans", XLFD_AddStyle);
  685.       }
  686.  
  687.    /*
  688.     * prefer normal values for other fields.  These only have an effect
  689.     * for fields that were wildcarded when requesting the font list.
  690.     */
  691.    PREFER("r", XLFD_Slant);        /* prefer roman slant */
  692.    PREFER("medium", XLFD_Weight);    /* prefer medium weight */
  693.    SPURN("demi", XLFD_Weight);        /* prefer non-demi if no medium */
  694.    PREFER("normal", XLFD_SetWidth);    /* prefer normal width */
  695.    PREFER("iso8859", XLFD_CharSet);    /* prefer font of ASCII chars */
  696.    SPURN("0", XLFD_PointSize);        /* prefer tuned font to scaled */
  697.    PREFER("adobe", XLFD_Foundry);    /* these look better than others */
  698.  
  699.    /* no significant difference */
  700.    return 0;
  701.    }
  702.  
  703. /*
  704.  * load a font and return a font structure.
  705.  */
  706.  
  707. wfp tryfont(w,s)
  708. wbp w;
  709. char *s;
  710.    {
  711.    wdp wd = w->window->display;
  712.    wfp rv;
  713.    /*
  714.     * see if the font is already loaded on this display
  715.     */
  716.    for(rv = wd->fonts; rv != NULL; rv = rv->next) {
  717.       if (!strcmp(s,rv->name)) break;
  718.       }
  719.    if (rv != NULL) {
  720.       rv->refcount++;
  721.       return rv;
  722.       }
  723.  
  724.    /*
  725.     * load a new font
  726.     */
  727.    GRFX_ALLOC(rv, _wfont);
  728.    rv->name = (char *)malloc((int)strlen(s)+1);
  729.    if (rv->name == NULL) ReturnErrNum(305, NULL);
  730.    strcpy(rv->name, s);
  731.    rv->fsp = XLoadQueryFont(wd->display, rv->name);
  732.    if (rv->fsp == NULL){
  733.       free(rv->name);
  734.       free(rv);
  735.       return NULL;
  736.       }
  737.    rv->height = rv->fsp->ascent + rv->fsp->descent;
  738.    w->context->leading = rv->height;
  739.  
  740.    /*
  741.     * link the font into this displays fontlist (but not at the head!)
  742.     */
  743.    rv->next = wd->fonts->next;
  744.    rv->previous = wd->fonts;
  745.    if (wd->fonts->next) wd->fonts->next->previous = rv;
  746.    wd->fonts->next = rv;
  747.    return rv;
  748.    }
  749.  
  750. /*
  751.  * allocate a context.  Can't be called until w has a display and window.
  752.  */
  753. wcp alc_context(w)
  754. wbp w;
  755.    {
  756.    int i;
  757.    wcp wc;
  758.    wdp wd = w->window->display;
  759.  
  760.    GRFX_ALLOC(wc, _wcontext);
  761.    wc->serial = ++context_serial;
  762.    wc->display = wd;
  763.    wd->refcount++;
  764.    wc->fg = &(wd->colors[0]);
  765.    wc->fg->refcount++;
  766.    wc->bg = &(wd->colors[1]);
  767.    wc->bg->refcount++;
  768.    wc->font = wd->fonts;
  769.    wc->leading = wd->fonts->height;
  770.    wc->drawop = GXcopy;
  771.    wc->gamma = wd->gamma;
  772.    wc->clipx = wc->clipy = 0;
  773.    wc->clipw = wc->cliph = -1;
  774.    wc->linewidth = 1;
  775.  
  776.    GRFX_LINK(wc, wcntxts);
  777.    return wc;
  778.    }
  779.  
  780. /*
  781.  * allocate a context, cloning attributes from an existing context
  782.  */
  783. wcp clone_context(w)
  784. wbp w;
  785.    {
  786.    wcp wc, rv;
  787.    XGCValues gcv;
  788.    XRectangle rec;
  789.    unsigned long gcmask = GCFont | GCForeground | GCBackground |
  790.         GCFillStyle | GCCapStyle | GCLineWidth | GCLineStyle;
  791.  
  792.    wc = w->context;
  793.    Protect(rv = alc_context(w), return NULL);
  794.  
  795.    rv->dx = wc->dx;
  796.    rv->dy = wc->dy;
  797.    rv->clipx = wc->clipx;
  798.    rv->clipy = wc->clipy;
  799.    rv->clipw = wc->clipw;
  800.    rv->cliph = wc->cliph;
  801.    rv->fg = wc->fg;
  802.    rv->fg->refcount++;
  803.    rv->bg = wc->bg;
  804.    rv->bg->refcount++;
  805.    rv->font = wc->font;
  806.    rv->font->refcount++;
  807.    rv->fillstyle = wc->fillstyle;
  808.    rv->linestyle = wc->linestyle;
  809.    rv->linewidth = wc->linewidth;
  810.    rv->drawop = wc->drawop;
  811.    rv->gamma = wc->gamma;
  812.    rv->bits = wc->bits;
  813.  
  814.    if (ISXORREVERSE(w))
  815.       gcv.foreground = rv->fg->c ^ rv->bg->c;
  816.    else
  817.       gcv.foreground = rv->fg->c;
  818.    gcv.background = rv->bg->c;
  819.    gcv.font       = rv->font->fsp->fid;
  820.    gcv.line_style = rv->linestyle;
  821.    gcv.line_width = rv->linewidth;
  822.    if (rv->linewidth > 1) {
  823.       gcv.dashes = 3 * rv->linewidth;
  824.       gcmask |= GCDashList;
  825.       }
  826.    gcv.fill_style = rv->fillstyle;
  827.    gcv.cap_style  = CapProjecting;
  828.    rv->gc = XCreateGC(w->window->display->display,w->window->pix,gcmask,&gcv);
  829.    if (rv->gc == NULL) {
  830.       free(rv);
  831.       return NULL;
  832.       }
  833.    if (rv->clipw >= 0) {
  834.       rec.x = rv->clipx;
  835.       rec.y = rv->clipy;
  836.       rec.width = rv->clipw;
  837.       rec.height = rv->cliph;
  838.       XSetClipRectangles(rv->display->display, rv->gc, 0, 0, &rec, 1,Unsorted);
  839.       }
  840.    return rv;
  841.    }
  842.  
  843. /*
  844.  * allocate a window state structure
  845.  */
  846. wsp alc_winstate()
  847.    {
  848.    int i;
  849.    wsp ws;
  850.    
  851.    GRFX_ALLOC(ws, _wstate);
  852.    ws->serial = ++canvas_serial;
  853.    ws->bits = 1024;                /* echo ON; others OFF */
  854.    ws->filep = nulldesc;
  855.    ws->listp = nulldesc;
  856.    ws->theCursor = si_s2i(cursorsyms, "left ptr") >> 1;
  857.    ws->iconic = NormalState;
  858.    ws->posx = ws->posy = -(MaxInt);
  859.    GRFX_LINK(ws, wstates);
  860.    return ws;
  861.    }
  862.  
  863. /*
  864.  * free a window state
  865.  */
  866. int free_window(ws)
  867. wsp ws;
  868.    {
  869.    ws->refcount--;
  870.    if(ws->refcount == 0) {
  871.       ws->bits |= 1;            /* SETZOMBIE */
  872.       if (ws->win != (Window) NULL) {
  873.      XDestroyWindow(ws->display->display, ws->win);
  874.      XFlush(ws->display->display);
  875.      while (ws->win != (Window) NULL)
  876.         if (pollevent() == -1) return -1;
  877.      }
  878.       GRFX_UNLINK(ws, wstates);
  879.       }
  880.    return 0;
  881.    }
  882.  
  883. /*
  884.  * free a window context
  885.  */
  886. novalue free_context(wc)
  887. wcp wc;
  888.    {
  889.    wc->refcount--;
  890.    if(wc->refcount == 0) {
  891.       if (wc->gc != NULL)
  892.      XFreeGC(wc->display->display, wc->gc);
  893.       free_display(wc->display);
  894.       GRFX_UNLINK(wc, wcntxts);
  895.       }
  896.    }
  897.  
  898. /*
  899.  * free a display
  900.  */
  901. novalue free_display(wd)
  902. wdp wd;
  903.    {
  904.    wd->refcount--;
  905.    if(wd->refcount == 0) {
  906.       if (wd->cmap != DefaultColormap(wd->display, wd->screen))
  907.      XFreeColormap(wd->display, wd->cmap);
  908.       XCloseDisplay(wd->display);
  909.       if (wd->previous) wd->previous->next = wd->next;
  910.       else wdsplys = wd->next;
  911.       if (wd->next) wd->next->previous = wd->previous;
  912.       free(wd);
  913.       }
  914.    }
  915.