Added missing newline in NEDsim error message.
[screensavers] / screenhack / font-retry.c
CommitLineData
3144ee8a
AT
1/* xscreensaver, Copyright (c) 2018-2020 by Jamie Zawinski <jwz@jwz.org>
2 *
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
9 * implied warranty.
10 */
11
12/* Like XLoadQueryFont, but if it fails, it tries some heuristics to
13 load something close.
14 */
15
16#define _GNU_SOURCE
17
18#include "utils.h"
19#include "visual.h"
20#include "xft.h"
21#include "font-retry.h"
22
23extern const char *progname;
24
25#undef countof
26#define countof(x) (sizeof((x))/sizeof((*x)))
27
28#undef DEBUG
29
30static void *
31load_font_retry_1 (Display *dpy, int screen, const char *xlfd, Bool xft_p)
32{
33
34# ifdef USE_XFT
35# define LOADFONT(F) (xft_p \
36 ? (void *) XftFontOpenXlfd (dpy, screen, (F)) \
37 : (void *) XLoadQueryFont (dpy, (F)))
38# else
39# define LOADFONT(F) ((void *) XLoadQueryFont (dpy, (F)))
40# endif
41
42 void *f = xlfd ? LOADFONT(xlfd) : 0;
43
44# ifndef USE_XFT
45 if (xft_p) abort();
46# endif
47
48# ifdef HAVE_JWXYZ
49 return f;
50# else /* !HAVE_JWXYZ */
51 if (! xlfd) xlfd = "<null>";
52 if (f)
53 {
54# ifdef DEBUG
55 fprintf (stderr, "%s: loaded %s\n", progname, xlfd);
56# endif
57 return f;
58 }
59 else
60 {
61 Bool bold_p = (!!strcasestr (xlfd, "-bold-") ||
62 !!strcasestr (xlfd, "-ocr"));
63 Bool italic_p = (!!strcasestr (xlfd, "-i-") ||
64 !!strcasestr (xlfd, "-o-"));
65 Bool fixed_p = (!!strcasestr (xlfd, "courier") ||
66 !!strcasestr (xlfd, "-ocr") ||
67 !!strcasestr (xlfd, "-m-") ||
68 !!strcasestr (xlfd, "-c-"));
69 int size = 0;
70
71# ifdef DEBUG
72 fprintf (stderr, "%s: failed %s\n", progname, xlfd);
73# endif
74
75 if (!strcmp (xlfd, "vga")) /* BSOD uses this: it has no XLFD name. */
76 fixed_p = True, size = 120;
77
78 /* Look for the first number in the string like "-180-" */
79 if (! size)
80 {
81 const char *s;
82 for (s = xlfd; *s; s++)
83 if (s[0] == '-' && s[1] >= '0' && s[1] <= '9')
84 {
85 int i = s[1] - '0';
86 const char *s2 = s+2;
87 while (*s2 >= '0' && *s2 <= '9')
88 {
89 i = i * 10 + *s2 - '0';
90 s2++;
91 }
92 if (*s2 != '-') continue; /* Number ends with dash */
93 if (i < 60 || i >= 2000) continue; /* In range 6pt - 200pt */
94 if (i % 10) continue; /* Multiple of 10 */
95
96 size = i;
97 break;
98 }
99 }
100
101 if (! size)
102 {
103 fprintf (stderr, "%s: unloadable, unparsable font: \"%s\"\n",
104 progname, xlfd);
105 xlfd = "fixed";
106 return LOADFONT(xlfd);
107 }
108 else
109 {
110 const char *variable[] = {
111 "helvetica",
112 "arial",
113 "bitstream vera sans", /* sometimes foundry is in family */
114 "vera sans", /* sometimes not? */
115 "gill sans",
116 "times",
117 "times new roman",
118 "new century schoolbook",
119 "utopia",
120 "palatino",
121 "lucida",
122 "clearlyu",
123 "bitstream charter", /* sometimes foundry is in family */
124 "charter", /* sometimes not? */
125 "utopia",
126 "luxi sans",
127 "latin modern roman",
128
129 /* Don't use a wildcard family. If none of the above worked, then
130 then almost none of the X11 fonts are installed, and it's not
131 unlikely that "-*-*-medium-r-*-*-*-140-*-*-*-10646-1" will
132 match an Arabic or or Japanese font that contains no Latin
133 glyphs at all, even in a Latin locale. So in that case, just
134 let "helvetica" fall back to "fixed".
135 */
136 /* "*" */
137 };
138 const char *fixed[] = {
139 "courier",
140 "courier new",
141 "courier 10 pitch",
142 "lucidatypewriter",
143 "american typewriter",
144 "luxi mono",
145 "fixed",
146 "ocr a std",
147 /* As above, but "can't happen" because we already tried fixed? */
148 /* "*" */
149 };
150 const char *charsets[] = { "iso10646-1", "iso8859-1", "*-*" };
151 const char *weights[] = { "bold", "medium" };
152 const char *slants[] = { "o", "i", "r" };
153 const char *spacings[] = { "m", "c", "p" };
154 int a, b, c, d, e, g;
155 char buf[1024];
156
157 for (a = 0; a < countof(charsets); a++)
158 for (b = (bold_p ? 0 : 1); b < countof(weights); b++)
159 for (c = (italic_p ? 0 : 2); c < countof(slants); c++)
160 for (d = 0;
161 d < (fixed_p ? countof(fixed) : countof(variable));
162 d++)
163 for (g = size; g >= 60; g -= 10)
164 for (e = (fixed_p ? 0 : 2); e < countof(spacings); e++)
165 {
166 sprintf (buf,
167 "-%s-%s-%s-%s-%s-%s-%s-%d-%s-%s-%s-%s-%s",
168 "*", /* foundry */
169 (fixed_p ? fixed[d] : variable[d]),
170 weights[b],
171 slants[c],
172 "*", /* set width */
173 "*", /* add style */
174 "*", /* pixel size */
175 g, /* point size */
176 "*", /* x resolution */
177 "*", /* y resolution */
178 spacings[e],
179 "*", /* average width */
180 charsets[a]);
181# ifdef DEBUG
182 fprintf(stderr, "%s: trying %s\n", progname, buf);
183# endif
184 f = LOADFONT(buf);
185 if (f)
186 {
187# ifdef DEBUG
188 fprintf (stderr,
189 "%s: substituted \"%s\" for \"%s\"\n",
190 progname, buf, xlfd);
191# endif
192 return f;
193 }
194 }
195
196 fprintf (stderr, "%s: unable to find any alternatives to \"%s\"\n",
197 progname, xlfd);
198 xlfd = "fixed";
199 return LOADFONT(xlfd);
200 }
201 }
202# endif /* !HAVE_JWXYZ */
203}
204
205XFontStruct *
206load_font_retry (Display *dpy, const char *xlfd)
207{
208 return (XFontStruct *) load_font_retry_1 (dpy, 0, xlfd, 0);
209}
210
211#ifdef USE_XFT
212XftFont *
213load_xft_font_retry (Display *dpy, int screen, const char *xlfd)
214{
215 return (XftFont *) load_font_retry_1 (dpy, screen, xlfd, 1);
216}
217
218#elif defined(HAVE_JWXYZ)
219
220XftFont *
221load_xft_font_retry (Display *dpy, int screen, const char *xlfd)
222{
223 return XftFontOpenXlfd (dpy, screen, xlfd);
224}
225
226#endif /* !HAVE_JWXYZ */