FLTK 1.3.9: fl_set_fonts_x.cxx Source File

FLTK 1.3.9

Loading...
Searching...
No Matches
fl_set_fonts_x.cxx
1//
2// "$Id$"
3//
4// X11 font utilities for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2010 by Bill Spitzak and others.
7//
8// This library is free software. Distribution and use rights are outlined in
9// the file "COPYING" which should have been included with this file. If this
10// file is missing or damaged, see the license at:
11//
12// http://www.fltk.org/COPYING.php
13//
14// Please report all bugs and problems on the following page:
15//
16// http://www.fltk.org/str.php
17//
18
19// This function fills in the fltk font table with all the fonts that
20// are found on the X server. It tries to place the fonts into families
21// and to sort them so the first 4 in a family are normal, bold, italic,
22// and bold italic.
23
24// Standard X fonts are matched by a pattern that is always of
25// this form, and this pattern is put in the table:
26// "-*-family-weight-slant-width1-style-*-registry-encoding"
27
28// Non-standard font names (those not starting with '-') are matched
29// by a pattern of the form "prefix*suffix", where the '*' is where
30// fltk thinks the point size is, or by the actual font name if no
31// point size is found.
32
33// Fltk knows how to pull an "attribute" out of a font name, such as
34// bold or italic, by matching known x font field values. All words
35// that don't match a known attribute are combined into the "name"
36// of the font. Names are compared before attributes for sorting, this
37// makes the bold and plain version of a font come out next to each
38// other despite the poor X font naming scheme.
39
40// By default fl_set_fonts() only does iso8859-1 encoded fonts. You can
41// do all normal X fonts by passing "-*" or every possible font with "*".
42
43// Fl::set_font will take strings other than the ones this stores
44// and can identify any font on X that way. You may want to write your
45// own system of font management and not use this code.
46
47// turn word N of a X font name into either some attribute bits
48// (right now 0, FL_BOLD, or FL_ITALIC), or into -1 indicating that
49// the word should be put into the name:
50
51static int attribute(int n, const char *p) {
52 // don't put blank things into name:
53 if (!*p || *p=='-' || *p=='*') return 0;
54 if (n == 3) { // weight
55 if (!strncmp(p,"normal",6) ||
56 !strncmp(p,"light",5) ||
57 !strncmp(p,"medium",6) ||
58 !strncmp(p,"book",4)) return 0;
59 if (!strncmp(p,"bold",4) || !strncmp(p,"demi",4)) return FL_BOLD;
60 } else if (n == 4) { // slant
61 if (*p == 'r') return 0;
62 if (*p == 'i' || *p == 'o') return FL_ITALIC;
63 } else if (n == 5) { // sWidth
64 if (!strncmp(p,"normal",6)) return 0;
65 }
66 return -1;
67}
68
69// return non-zero if the registry-encoding should be used:
70extern const char* fl_encoding;
71static int use_registry(const char *p) {
72 return *p && *p!='*' && strcmp(p,fl_encoding);
73}
74
75// Bug: older versions calculated the value for *ap as a side effect of
76// making the name, and then forgot about it. To avoid having to change
77// the header files I decided to store this value in the last character
78// of the font name array.
79#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1
80
81// turn a stored (with *'s) X font name into a pretty name:
82const char* Fl::get_font_name(Fl_Font fnum, int* ap) {
83 Fl_Fontdesc *f = fl_fonts + fnum;
84 if (!f->fontname[0]) {
85 int type = 0;
86 const char* p = f->name;
87 if (!p) {
88 if (ap) *ap = 0;
89 return "";
90 }
91 char *o = f->fontname;
92
93 if (*p != '-') { // non-standard font, just replace * with spaces:
94 if (strstr(p,"bold")) type = FL_BOLD;
95 if (strstr(p,"ital")) type |= FL_ITALIC;
96 for (;*p; p++) {
97 if (*p == '*' || *p == ' ' || *p == '-') {
98 do p++; while (*p == '*' || *p == ' ' || *p == '-');
99 if (!*p) break;
100 if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' ';
101 }
102 if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = *p;
103 }
104 *o = 0;
105
106 } else { // standard dash-separated font:
107
108 // get the family:
109 const char *x = fl_font_word(p,2); if (*x) x++; if (*x=='*') x++;
110 if (!*x) {
111 if (ap) *ap = 0;
112 return p;
113 }
114 const char *e = fl_font_word(x,1);
115 if ((e - x) < (int)(ENDOFBUFFER - 1)) {
116 // MRS: we want strncpy here, not strlcpy...
117 strncpy(o,x,e-x);
118 o += e-x;
119 } else {
120 strlcpy(f->fontname, x, ENDOFBUFFER);
121 o = f->fontname+ENDOFBUFFER-1;
122 }
123
124 // collect all the attribute words:
125 for (int n = 3; n <= 6; n++) {
126 // get the next word:
127 if (*e) e++;
128 x = e;
129 e = fl_font_word(x,1);
130 int t = attribute(n,x);
131 if (t < 0) {
132 if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' ';
133 if ((e - x) < (int)(ENDOFBUFFER - (o - f->fontname) - 1)) {
134 // MRS: we want strncpy here, not strlcpy...
135 strncpy(o,x,e-x);
136 o += e-x;
137 } else {
138 strlcpy(o,x, ENDOFBUFFER - (o - f->fontname) - 1);
139 o = f->fontname+ENDOFBUFFER-1;
140 }
141 } else type |= t;
142 }
143
144 // skip over the '*' for the size and get the registry-encoding:
145 x = fl_font_word(e,2);
146 if (*x) {x++; *o++ = '('; while (*x) *o++ = *x++; *o++ = ')';}
147
148 *o = 0;
149 if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER);
150 if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER);
151 }
152 f->fontname[ENDOFBUFFER] = (char)type;
153 }
154 if (ap) *ap = f->fontname[ENDOFBUFFER];
155 return f->fontname;
156}
157
158extern "C" {
159// sort raw (non-'*') X font names into perfect order:
160
161static int ultrasort(const void *aa, const void *bb) {
162 const char *a = *(char **)aa;
163 const char *b = *(char **)bb;
164
165 // sort all non x-fonts at the end:
166 if (*a != '-') {
167 if (*b == '-') return 1;
168 // 2 non-x fonts are matched by "numeric sort"
169 int ret = 0;
170 for (;;) {
171 if (isdigit(*a) && isdigit(*b)) {
172 int na = strtol(a, (char **)&a, 10);
173 int nb = strtol(b, (char **)&b, 10);
174 if (!ret) ret = na-nb;
175 } else if (*a != *b) {
176 return (*a-*b);
177 } else if (!*a) {
178 return ret;
179 } else {
180 a++; b++;
181 }
182 }
183 } else {
184 if (*b != '-') return -1;
185 }
186
187 // skip the foundry (assume equal):
188 for (a++; *a && *a++!='-';);
189 for (b++; *b && *b++!='-';);
190
191 // compare the family and all the attribute words:
192 int atype = 0;
193 int btype = 0;
194 for (int n = 2; n <= 6; n++) {
195 int at = attribute(n,a);
196 int bt = attribute(n,b);
197 if (at < 0) {
198 if (bt >= 0) return 1;
199 for (;;) {if (*a!=*b) return *a-*b; b++; if (!*a || *a++=='-') break;}
200 } else {
201 if (bt < 0) return -1;
202 a = fl_font_word(a,1); if (*a) a++;
203 b = fl_font_word(b,1); if (*b) b++;
204 atype |= at; btype |= bt;
205 }
206 }
207
208 // remember the pixel size:
209 int asize = atoi(a);
210 int bsize = atoi(b);
211
212 // compare the registry/encoding:
213 a = fl_font_word(a,6); if (*a) a++;
214 b = fl_font_word(b,6); if (*b) b++;
215 if (use_registry(a)) {
216 if (!use_registry(b)) return 1;
217 int r = strcmp(a,b); if (r) return r;
218 } else {
219 if (use_registry(b)) return -1;
220 }
221
222 if (atype != btype) return atype-btype;
223 if (asize != bsize) return asize-bsize;
224
225 // something wrong, just do a string compare...
226 return strcmp(*(char**)aa, *(char**)bb);
227}
228}
229
230// converts a X font name to a standard starname, returns point size:
231static int to_canonical(char *to, const char *from, size_t tolen) {
232 char* c = fl_find_fontsize((char*)from);
233 if (!c) return -1; // no point size found...
234 const char* endptr;
235 int size = strtol(c,(char**)&endptr,10);
236 if (from[0] == '-') {
237 // replace the "foundry" with -*-:
238 *to++ = '-'; *to++ = '*';
239 for (from++; *from && *from != '-'; from++);
240 // skip to the registry-encoding:
241 endptr = (char*)fl_font_word(endptr,6);
242 if (*endptr && !use_registry(endptr+1)) endptr = "";
243 }
244 int n = c-from;
245 // MRS: we want strncpy here, not strlcpy...
246 if (n > (int)(tolen - 1)) return -1;
247 strncpy(to,from,n);
248 to[n++] = '*';
249 strlcpy(to+n,endptr, tolen - n);
250 return size;
251}
252
253static unsigned int fl_free_font = FL_FREE_FONT;
254
255 Fl_Font Fl::set_fonts(const char* xstarname) {
256 if (fl_free_font > (unsigned)FL_FREE_FONT) // already been here
257 return (Fl_Font)fl_free_font;
258 fl_open_display();
259 int xlistsize;
260 char buf[20];
261 if (!xstarname) {
262 strcpy(buf,"-*-"); strcpy(buf+3,fl_encoding);
263 xstarname = buf;
264 }
265 char **xlist = XListFonts(fl_display, xstarname, 10000, &xlistsize);
266 if (!xlist) return (Fl_Font)fl_free_font;
267 qsort(xlist, xlistsize, sizeof(*xlist), ultrasort);
268 int used_xlist = 0;
269 for (int i=0; i<xlistsize;) {
270 int first_xlist = i;
271 const char *p = xlist[i++];
272 char canon[1024];
273 int size = to_canonical(canon, p, sizeof(canon));
274 if (size >= 0) {
275 for (;;) { // find all matching fonts:
276 if (i >= xlistsize) break;
277 const char *q = xlist[i];
278 char this_canon[1024];
279 if (to_canonical(this_canon, q, sizeof(this_canon)) < 0) break;
280 if (strcmp(canon, this_canon)) break;
281 i++;
282 }
283 /*if (*p=='-' || i > first_xlist+1)*/ p = canon;
284 }
285 unsigned int j;
286 for (j = 0;; j++) {
287 /*if (j < FL_FREE_FONT) {
288 // see if it is one of our built-in fonts:
289 // if so, set the list of x fonts, since we have it anyway
290 if (fl_fonts[j].name && !strcmp(fl_fonts[j].name, p)) break;
291 } else */{
292 j = fl_free_font++;
293 if (p == canon) p = strdup(p); else used_xlist = 1;
294 Fl::set_font((Fl_Font)j, p);
295 break;
296 }
297 }
298 if (!fl_fonts[j].xlist) {
299 fl_fonts[j].xlist = xlist+first_xlist;
300 fl_fonts[j].n = -(i-first_xlist);
301 used_xlist = 1;
302 }
303 }
304 if (!used_xlist) XFreeFontNames(xlist);
305 return (Fl_Font)fl_free_font;
306}
307
308int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) {
309 Fl_Fontdesc *s = fl_fonts+fnum;
310 if (!s->name) s = fl_fonts; // empty slot in table, use entry 0
311 if (!s->xlist) {
312 fl_open_display();
313 s->xlist = XListFonts(fl_display, s->name, 100, &(s->n));
314 if (!s->xlist) return 0;
315 }
316 int listsize = s->n; if (listsize<0) listsize = -listsize;
317 static int sizes[128];
318 int numsizes = 0;
319 for (int i = 0; i < listsize; i++) {
320 char *q = s->xlist[i];
321 char *d = fl_find_fontsize(q);
322 if (!d) continue;
323 int s = strtol(d,0,10);
324 if (!numsizes || sizes[numsizes-1] < s) {
325 sizes[numsizes++] = s;
326 } else {
327 // insert-sort the new size into list:
328 int n;
329 for (n = numsizes-1; n > 0; n--) if (sizes[n-1] < s) break;
330 if (sizes[n] != s) {
331 for (int m = numsizes; m > n; m--) sizes[m] = sizes[m-1];
332 sizes[n] = s;
333 numsizes++;
334 }
335 }
336 }
337 sizep = sizes;
338 return numsizes;
339}
340
341//
342// End of "$Id$".
343//
Fl_Font
int Fl_Font
A font number is an index into the internal font table.
Definition Enumerations.H:875
FL_BOLD
const Fl_Font FL_BOLD
add this to helvetica, courier, or times
Definition Enumerations.H:895
FL_ITALIC
const Fl_Font FL_ITALIC
add this to helvetica, courier, or times
Definition Enumerations.H:896
FL_FREE_FONT
const Fl_Font FL_FREE_FONT
first one to allocate
Definition Enumerations.H:894
Fl::set_font
static void set_font(Fl_Font, const char *)
Changes a face.
Definition fl_set_font.cxx:34
Fl::get_font_sizes
static int get_font_sizes(Fl_Font, int *&sizep)
Return an array of sizes in sizep.
Definition fl_set_fonts_mac.cxx:188
Fl::get_font_name
static const char * get_font_name(Fl_Font, int *attributes=0)
Get a human-readable string describing the family of this face.
Definition fl_set_fonts_mac.cxx:31
Fl::set_fonts
static Fl_Font set_fonts(const char *=0)
FLTK will open the display, and add every fonts on the server to the face table.
Definition fl_set_fonts_mac.cxx:108
Fl::x
static int x()
Returns the leftmost x coordinate of the main screen work area.
Fl_Fontdesc
Definition Fl_Font.H:86