2 // "$Id: fl_set_fonts_x.cxx 8037 2010-12-15 13:54:34Z manolo $"
4 // X11 font utilities for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
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.
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.
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
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
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,
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"
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.
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.
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 "*".
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.
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:
60 static 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;
78 // return non-zero if the registry-encoding should be used:
79 extern const char* fl_encoding
;
80 static int use_registry(const char *p
) {
81 return *p
&& *p
!='*' && strcmp(p
,fl_encoding
);
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
90 // turn a stored (with *'s) X font name into a pretty name:
91 const char* Fl::get_font_name(Fl_Font fnum
, int* ap
) {
92 Fl_Fontdesc
*f
= fl_fonts
+ fnum
;
93 if (!f
->fontname
[0]) {
95 const char* p
= f
->name
;
100 char *o
= f
->fontname
;
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
;
106 if (*p
== '*' || *p
== ' ' || *p
== '-') {
107 do p
++; while (*p
== '*' || *p
== ' ' || *p
== '-');
109 if (o
< (f
->fontname
+ ENDOFBUFFER
- 1)) *o
++ = ' ';
111 if (o
< (f
->fontname
+ ENDOFBUFFER
- 1)) *o
++ = *p
;
115 } else { // standard dash-separated font:
118 const char *x
= fl_font_word(p
,2); if (*x
) x
++; if (*x
=='*') x
++;
123 const char *e
= fl_font_word(x
,1);
124 if ((e
- x
) < (int)(ENDOFBUFFER
- 1)) {
125 // MRS: we want strncpy here, not strlcpy...
129 strlcpy(f
->fontname
, x
, ENDOFBUFFER
);
130 o
= f
->fontname
+ENDOFBUFFER
-1;
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
);
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...
145 strlcpy(o
,x
, ENDOFBUFFER
- (o
- f
->fontname
) - 1);
146 o
= f
->fontname
+ENDOFBUFFER
-1;
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
++ = ')';}
156 if (type
& FL_BOLD
) strlcat(f
->fontname
, " bold", ENDOFBUFFER
);
157 if (type
& FL_ITALIC
) strlcat(f
->fontname
, " italic", ENDOFBUFFER
);
159 f
->fontname
[ENDOFBUFFER
] = (char)type
;
161 if (ap
) *ap
= f
->fontname
[ENDOFBUFFER
];
166 // sort raw (non-'*') X font names into perfect order:
168 static int ultrasort(const void *aa
, const void *bb
) {
169 const char *a
= *(char **)aa
;
170 const char *b
= *(char **)bb
;
172 // sort all non x-fonts at the end:
174 if (*b
== '-') return 1;
175 // 2 non-x fonts are matched by "numeric sort"
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
) {
191 if (*b
!= '-') return -1;
194 // skip the foundry (assume equal):
195 for (a
++; *a
&& *a
++!='-';);
196 for (b
++; *b
&& *b
++!='-';);
198 // compare the family and all the attribute words:
201 for (int n
= 2; n
<= 6; n
++) {
202 int at
= attribute(n
,a
);
203 int bt
= attribute(n
,b
);
205 if (bt
>= 0) return 1;
206 for (;;) {if (*a
!=*b
) return *a
-*b
; b
++; if (!*a
|| *a
++=='-') break;}
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
;
215 // remember the pixel size:
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
;
226 if (use_registry(b
)) return -1;
229 if (atype
!= btype
) return atype
-btype
;
230 if (asize
!= bsize
) return asize
-bsize
;
232 // something wrong, just do a string compare...
233 return strcmp(*(char**)aa
, *(char**)bb
);
237 // converts a X font name to a standard starname, returns point size:
238 static 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...
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
= "";
252 // MRS: we want strncpy here, not strlcpy...
253 if (n
> (int)(tolen
- 1)) return -1;
256 strlcpy(to
+n
,endptr
, tolen
- n
);
260 static unsigned int fl_free_font
= FL_FREE_FONT
;
262 Fl_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
;
269 strcpy(buf
,"-*-"); strcpy(buf
+3,fl_encoding
);
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
);
276 for (int i
=0; i
<xlistsize
;) {
278 const char *p
= xlist
[i
++];
280 int size
= to_canonical(canon
, p
, sizeof(canon
));
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;
290 /*if (*p=='-' || i > first_xlist+1)*/ p
= canon
;
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;
300 if (p
== canon
) p
= strdup(p
); else used_xlist
= 1;
301 Fl::set_font((Fl_Font
)j
, p
);
305 if (!fl_fonts
[j
].xlist
) {
306 fl_fonts
[j
].xlist
= xlist
+first_xlist
;
307 fl_fonts
[j
].n
= -(i
-first_xlist
);
311 if (!used_xlist
) XFreeFontNames(xlist
);
312 return (Fl_Font
)fl_free_font
;
315 int 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
320 s
->xlist
= XListFonts(fl_display
, s
->name
, 100, &(s
->n
));
321 if (!s
->xlist
) return 0;
323 int listsize
= s
->n
; if (listsize
<0) listsize
= -listsize
;
324 static int sizes
[128];
326 for (int i
= 0; i
< listsize
; i
++) {
327 char *q
= s
->xlist
[i
];
328 char *d
= fl_find_fontsize(q
);
330 int s
= strtol(d
,0,10);
331 if (!numsizes
|| sizes
[numsizes
-1] < s
) {
332 sizes
[numsizes
++] = s
;
334 // insert-sort the new size into list:
336 for (n
= numsizes
-1; n
> 0; n
--) if (sizes
[n
-1] < s
) break;
338 for (int m
= numsizes
; m
> n
; m
--) sizes
[m
] = sizes
[m
-1];
349 // End of "$Id: fl_set_fonts_x.cxx 8037 2010-12-15 13:54:34Z manolo $".