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