fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

fl_set_fonts_x.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: fl_set_fonts_x.cxx 8037 2010-12-15 13:54:34Z manolo $"
00003 //
00004 // X11 font utilities for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 // This function fills in the fltk font table with all the fonts that
00029 // are found on the X server.  It tries to place the fonts into families
00030 // and to sort them so the first 4 in a family are normal, bold, italic,
00031 // and bold italic.
00032 
00033 // Standard X fonts are matched by a pattern that is always of
00034 // this form, and this pattern is put in the table:
00035 // "-*-family-weight-slant-width1-style-*-registry-encoding"
00036 
00037 // Non-standard font names (those not starting with '-') are matched
00038 // by a pattern of the form "prefix*suffix", where the '*' is where
00039 // fltk thinks the point size is, or by the actual font name if no
00040 // point size is found.
00041 
00042 // Fltk knows how to pull an "attribute" out of a font name, such as
00043 // bold or italic, by matching known x font field values.  All words
00044 // that don't match a known attribute are combined into the "name"
00045 // of the font.  Names are compared before attributes for sorting, this
00046 // makes the bold and plain version of a font come out next to each
00047 // other despite the poor X font naming scheme.
00048 
00049 // By default fl_set_fonts() only does iso8859-1 encoded fonts.  You can
00050 // do all normal X fonts by passing "-*" or every possible font with "*".
00051 
00052 // Fl::set_font will take strings other than the ones this stores
00053 // and can identify any font on X that way.  You may want to write your
00054 // own system of font management and not use this code.
00055 
00056 // turn word N of a X font name into either some attribute bits
00057 // (right now 0, FL_BOLD, or FL_ITALIC), or into -1 indicating that
00058 // the word should be put into the name:
00059 
00060 static int attribute(int n, const char *p) {
00061   // don't put blank things into name:
00062   if (!*p || *p=='-' || *p=='*') return 0;
00063   if (n == 3) { // weight
00064     if (!strncmp(p,"normal",6) ||
00065         !strncmp(p,"light",5) ||
00066         !strncmp(p,"medium",6) ||
00067         !strncmp(p,"book",4)) return 0;
00068     if (!strncmp(p,"bold",4) || !strncmp(p,"demi",4)) return FL_BOLD;
00069   } else if (n == 4) { // slant
00070     if (*p == 'r') return 0;
00071     if (*p == 'i' || *p == 'o') return FL_ITALIC;
00072   } else if (n == 5) { // sWidth
00073     if (!strncmp(p,"normal",6)) return 0;
00074   }
00075   return -1;
00076 }
00077 
00078 // return non-zero if the registry-encoding should be used:
00079 extern const char* fl_encoding;
00080 static int use_registry(const char *p) {
00081   return *p && *p!='*' && strcmp(p,fl_encoding);
00082 }
00083 
00084 // Bug: older versions calculated the value for *ap as a side effect of
00085 // making the name, and then forgot about it. To avoid having to change
00086 // the header files I decided to store this value in the last character
00087 // of the font name array.
00088 #define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1
00089 
00090 // turn a stored (with *'s) X font name into a pretty name:
00091 const char* Fl::get_font_name(Fl_Font fnum, int* ap) {
00092   Fl_Fontdesc *f = fl_fonts + fnum;
00093   if (!f->fontname[0]) {
00094     int type = 0;
00095     const char* p = f->name;
00096     if (!p) {
00097       if (ap) *ap = 0;
00098       return "";
00099     }
00100     char *o = f->fontname;
00101 
00102     if (*p != '-') { // non-standard font, just replace * with spaces:
00103       if (strstr(p,"bold")) type = FL_BOLD;
00104       if (strstr(p,"ital")) type |= FL_ITALIC;
00105       for (;*p; p++) {
00106         if (*p == '*' || *p == ' ' || *p == '-') {
00107           do p++; while (*p == '*' || *p == ' ' || *p == '-');
00108           if (!*p) break;
00109           if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' ';
00110         }
00111         if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = *p;
00112       }
00113       *o = 0;
00114 
00115     } else { // standard dash-separated font:
00116 
00117       // get the family:
00118       const char *x = fl_font_word(p,2); if (*x) x++; if (*x=='*') x++;
00119       if (!*x) {
00120         if (ap) *ap = 0;
00121         return p;
00122       }
00123       const char *e = fl_font_word(x,1);
00124       if ((e - x) < (int)(ENDOFBUFFER - 1)) {
00125         // MRS: we want strncpy here, not strlcpy...
00126         strncpy(o,x,e-x);
00127         o += e-x;
00128       } else {
00129         strlcpy(f->fontname, x, ENDOFBUFFER);
00130         o = f->fontname+ENDOFBUFFER-1;
00131       }
00132 
00133       // collect all the attribute words:
00134       for (int n = 3; n <= 6; n++) {
00135         // get the next word:
00136         if (*e) e++; x = e; e = fl_font_word(x,1);
00137         int t = attribute(n,x);
00138         if (t < 0) {
00139           if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' ';
00140           if ((e - x) < (int)(ENDOFBUFFER - (o - f->fontname) - 1)) {
00141             // MRS: we want strncpy here, not strlcpy...
00142             strncpy(o,x,e-x);
00143             o += e-x;
00144           } else {
00145             strlcpy(o,x, ENDOFBUFFER - (o - f->fontname) - 1);
00146             o = f->fontname+ENDOFBUFFER-1;
00147           }
00148         } else type |= t;
00149       }
00150 
00151       // skip over the '*' for the size and get the registry-encoding:
00152       x = fl_font_word(e,2);
00153       if (*x) {x++; *o++ = '('; while (*x) *o++ = *x++; *o++ = ')';}
00154 
00155       *o = 0;
00156       if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER);
00157       if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER);
00158     }
00159     f->fontname[ENDOFBUFFER] = (char)type;
00160   }
00161   if (ap) *ap = f->fontname[ENDOFBUFFER];
00162   return f->fontname;
00163 }
00164 
00165 extern "C" {
00166 // sort raw (non-'*') X font names into perfect order:
00167 
00168 static int ultrasort(const void *aa, const void *bb) {
00169   const char *a = *(char **)aa;
00170   const char *b = *(char **)bb;
00171 
00172   // sort all non x-fonts at the end:
00173   if (*a != '-') {
00174     if (*b == '-') return 1;
00175     // 2 non-x fonts are matched by "numeric sort"
00176     int ret = 0;
00177     for (;;) {
00178       if (isdigit(*a) && isdigit(*b)) {
00179         int na = strtol(a, (char **)&a, 10);
00180         int nb = strtol(b, (char **)&b, 10);
00181         if (!ret) ret = na-nb;
00182       } else if (*a != *b) {
00183         return (*a-*b);
00184       } else if (!*a) {
00185         return ret;
00186       } else {
00187         a++; b++;
00188       }
00189     }
00190   } else {
00191     if (*b != '-') return -1;
00192   }
00193 
00194   // skip the foundry (assume equal):
00195   for (a++; *a && *a++!='-';);
00196   for (b++; *b && *b++!='-';);
00197 
00198   // compare the family and all the attribute words:
00199   int atype = 0;
00200   int btype = 0;
00201   for (int n = 2; n <= 6; n++) {
00202     int at = attribute(n,a);
00203     int bt = attribute(n,b);
00204     if (at < 0) {
00205       if (bt >= 0) return 1;
00206       for (;;) {if (*a!=*b) return *a-*b; b++; if (!*a || *a++=='-') break;}
00207     } else {
00208       if (bt < 0) return -1;
00209       a = fl_font_word(a,1); if (*a) a++;
00210       b = fl_font_word(b,1); if (*b) b++;
00211       atype |= at; btype |= bt;
00212     }
00213   }
00214 
00215   // remember the pixel size:
00216   int asize = atoi(a);
00217   int bsize = atoi(b);
00218 
00219   // compare the registry/encoding:
00220   a = fl_font_word(a,6); if (*a) a++;
00221   b = fl_font_word(b,6); if (*b) b++;
00222   if (use_registry(a)) {
00223     if (!use_registry(b)) return 1;
00224     int r = strcmp(a,b); if (r) return r;
00225   } else {
00226     if (use_registry(b)) return -1;
00227   }
00228 
00229   if (atype != btype) return atype-btype;
00230   if (asize != bsize) return asize-bsize;
00231 
00232   // something wrong, just do a string compare...
00233   return strcmp(*(char**)aa, *(char**)bb);
00234 }
00235 }
00236 
00237 // converts a X font name to a standard starname, returns point size:
00238 static int to_canonical(char *to, const char *from, size_t tolen) {
00239   char* c = fl_find_fontsize((char*)from);
00240   if (!c) return -1; // no point size found...
00241   const char* endptr;
00242   int size = strtol(c,(char**)&endptr,10);
00243   if (from[0] == '-') {
00244     // replace the "foundry" with -*-:
00245     *to++ = '-'; *to++ = '*';
00246     for (from++; *from && *from != '-'; from++);
00247     // skip to the registry-encoding:
00248     endptr = (char*)fl_font_word(endptr,6);
00249     if (*endptr && !use_registry(endptr+1)) endptr = "";
00250   }
00251   int n = c-from;
00252   // MRS: we want strncpy here, not strlcpy...
00253   if (n > (int)(tolen - 1)) return -1;
00254   strncpy(to,from,n);
00255   to[n++] = '*';
00256   strlcpy(to+n,endptr, tolen - n);
00257   return size;
00258 }
00259 
00260 static unsigned int fl_free_font = FL_FREE_FONT;
00261 
00262 Fl_Font Fl::set_fonts(const char* xstarname) {
00263   if (fl_free_font > (unsigned)FL_FREE_FONT) // already been here
00264     return (Fl_Font)fl_free_font;
00265   fl_open_display();
00266   int xlistsize;
00267   char buf[20];
00268   if (!xstarname) {
00269     strcpy(buf,"-*-"); strcpy(buf+3,fl_encoding);
00270     xstarname = buf;
00271   }
00272   char **xlist = XListFonts(fl_display, xstarname, 10000, &xlistsize);
00273   if (!xlist) return (Fl_Font)fl_free_font;
00274   qsort(xlist, xlistsize, sizeof(*xlist), ultrasort);
00275   int used_xlist = 0;
00276   for (int i=0; i<xlistsize;) {
00277     int first_xlist = i;
00278     const char *p = xlist[i++];
00279     char canon[1024];
00280     int size = to_canonical(canon, p, sizeof(canon));
00281     if (size >= 0) {
00282       for (;;) { // find all matching fonts:
00283         if (i >= xlistsize) break;
00284         const char *q = xlist[i];
00285         char this_canon[1024];
00286         if (to_canonical(this_canon, q, sizeof(this_canon)) < 0) break;
00287         if (strcmp(canon, this_canon)) break;
00288         i++;
00289       }
00290       /*if (*p=='-' || i > first_xlist+1)*/ p = canon;
00291     }
00292     unsigned int j;
00293     for (j = 0;; j++) {
00294       /*if (j < FL_FREE_FONT) {
00295         // see if it is one of our built-in fonts:
00296         // if so, set the list of x fonts, since we have it anyway
00297         if (fl_fonts[j].name && !strcmp(fl_fonts[j].name, p)) break;
00298       } else */{
00299         j = fl_free_font++;
00300         if (p == canon) p = strdup(p); else used_xlist = 1;
00301         Fl::set_font((Fl_Font)j, p);
00302         break;
00303       }
00304     }
00305     if (!fl_fonts[j].xlist) {
00306       fl_fonts[j].xlist = xlist+first_xlist;
00307       fl_fonts[j].n = -(i-first_xlist);
00308       used_xlist = 1;
00309     }
00310   }
00311   if (!used_xlist) XFreeFontNames(xlist);
00312   return (Fl_Font)fl_free_font;
00313 }
00314 
00315 int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) {
00316   Fl_Fontdesc *s = fl_fonts+fnum;
00317   if (!s->name) s = fl_fonts; // empty slot in table, use entry 0
00318   if (!s->xlist) {
00319     fl_open_display();
00320     s->xlist = XListFonts(fl_display, s->name, 100, &(s->n));
00321     if (!s->xlist) return 0;
00322   }
00323   int listsize = s->n; if (listsize<0) listsize = -listsize;
00324   static int sizes[128];
00325   int numsizes = 0;
00326   for (int i = 0; i < listsize; i++) {
00327     char *q = s->xlist[i];
00328     char *d = fl_find_fontsize(q);
00329     if (!d) continue;
00330     int s = strtol(d,0,10);
00331     if (!numsizes || sizes[numsizes-1] < s) {
00332       sizes[numsizes++] = s;
00333     } else {
00334       // insert-sort the new size into list:
00335       int n;
00336       for (n = numsizes-1; n > 0; n--) if (sizes[n-1] < s) break;
00337       if (sizes[n] != s) {
00338         for (int m = numsizes; m > n; m--) sizes[m] = sizes[m-1];
00339         sizes[n] = s;
00340         numsizes++;
00341       }
00342     }
00343   }
00344   sizep = sizes;
00345   return numsizes;
00346 }
00347 
00348 //
00349 // End of "$Id: fl_set_fonts_x.cxx 8037 2010-12-15 13:54:34Z manolo $".
00350 //