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