check encoding in EnumerateFacenames(); implemented EnumerateEncodings() for wxUSE_PA...
[wxWidgets.git] / src / unix / fontenum.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/fontenum.cpp
3 // Purpose: wxFontEnumerator class for X11/GDK
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 01.10.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #include "wx/fontenum.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/dynarray.h"
27 #include "wx/string.h"
28 #include "wx/app.h"
29 #include "wx/utils.h"
30 #endif
31
32 #include "wx/regex.h"
33 #include "wx/fontmap.h"
34 #include "wx/fontutil.h"
35 #include "wx/encinfo.h"
36
37 // ----------------------------------------------------------------------------
38 // Pango
39 // ----------------------------------------------------------------------------
40
41 #if wxUSE_PANGO
42
43 #include "pango/pango.h"
44
45 #ifdef __WXGTK20__
46 #include "gtk/gtk.h"
47 extern GtkWidget *wxGetRootWindow();
48 #endif // __WXGTK20__
49
50 extern "C" int wxCMPFUNC_CONV
51 wxCompareFamilies (const void *a, const void *b)
52 {
53 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
54 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
55
56 return g_utf8_collate (a_name, b_name);
57 }
58
59 bool wxFontEnumerator::EnumerateFacenames(wxFontEncoding encoding,
60 bool fixedWidthOnly)
61 {
62 if ( encoding != wxFONTENCODING_SYSTEM && encoding != wxFONTENCODING_UTF8 )
63 {
64 // Pango supports only UTF-8 encoding (and system means any, so we
65 // accept it too)
66 return false;
67 }
68
69 #if defined(__WXGTK20__) || !defined(HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE)
70 if ( fixedWidthOnly
71 #if defined(__WXGTK24__)
72 && (gtk_check_version(2,4,0) != NULL)
73 #endif
74 )
75 {
76 OnFacename( wxT("monospace") );
77 }
78 else // !fixedWidthOnly
79 #endif // __WXGTK20__ || !HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE
80 {
81 PangoFontFamily **families = NULL;
82 gint n_families = 0;
83 pango_context_list_families (
84 #ifdef __WXGTK20__
85 gtk_widget_get_pango_context( wxGetRootWindow() ),
86 #else
87 wxTheApp->GetPangoContext(),
88 #endif
89 &families, &n_families );
90 qsort (families, n_families, sizeof (PangoFontFamily *), wxCompareFamilies);
91
92 for (int i=0; i<n_families; i++)
93 {
94 #if defined(__WXGTK24__) || defined(HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE)
95 if (!fixedWidthOnly || (
96 #ifdef __WXGTK24__
97 !gtk_check_version(2,4,0) &&
98 #endif
99 pango_font_family_is_monospace(families[i])
100 ) )
101 #endif
102 {
103 const gchar *name = pango_font_family_get_name(families[i]);
104 OnFacename(wxString(name, wxConvUTF8));
105 }
106 }
107 g_free(families);
108 }
109
110 return true;
111 }
112
113 bool wxFontEnumerator::EnumerateEncodings(const wxString& facename)
114 {
115 // name of UTF-8 encoding: no need to use wxFontMapper for it as it's
116 // unlikely to change
117 const wxString utf8(_T("UTF-8"));
118
119
120 // all fonts are in UTF-8 only when using Pango
121 if ( !facename.empty() )
122 {
123 OnFontEncoding(facename, utf8);
124 return true;
125 }
126
127 // so enumerating all facenames supporting this encoding is the same as
128 // enumerating all facenames
129 const wxArrayString facenames(GetFacenames(wxFONTENCODING_UTF8));
130 const size_t count = facenames.size();
131 if ( !count )
132 return false;
133
134 for ( size_t n = 0; n < count; n++ )
135 {
136 OnFontEncoding(facenames[n], utf8);
137 }
138
139 return true;
140 }
141
142
143 #else // !wxUSE_PANGO
144
145 #ifdef __VMS__ // Xlib.h for VMS is not (yet) compatible with C++
146 // The resulting warnings are switched off here
147 #pragma message disable nosimpint
148 #endif
149 #include <X11/Xlib.h>
150 #ifdef __VMS__
151 #pragma message enable nosimpint
152 #endif
153
154 // ----------------------------------------------------------------------------
155 // private functions
156 // ----------------------------------------------------------------------------
157
158 // create the list of all fonts with the given spacing and encoding
159 static char **CreateFontList(wxChar spacing, wxFontEncoding encoding,
160 int *nFonts);
161
162 // extract all font families from the given font list and call our
163 // OnFacename() for each of them
164 static bool ProcessFamiliesFromFontList(wxFontEnumerator *This,
165 char **fonts,
166 int nFonts);
167
168
169 // ----------------------------------------------------------------------------
170 // private types
171 // ----------------------------------------------------------------------------
172
173 // ============================================================================
174 // implementation
175 // ============================================================================
176
177 // ----------------------------------------------------------------------------
178 // helpers
179 // ----------------------------------------------------------------------------
180
181 #if !wxUSE_NANOX
182 static char **CreateFontList(wxChar spacing,
183 wxFontEncoding encoding,
184 int *nFonts)
185 {
186 wxNativeEncodingInfo info;
187 wxGetNativeFontEncoding(encoding, &info);
188
189 #if wxUSE_FONTMAP
190 if ( !wxTestFontEncoding(info) )
191 {
192 // ask font mapper for a replacement
193 (void)wxFontMapper::Get()->GetAltForEncoding(encoding, &info);
194 }
195 #endif // wxUSE_FONTMAP
196
197 wxString pattern;
198 pattern.Printf(wxT("-*-*-*-*-*-*-*-*-*-*-%c-*-%s-%s"),
199 spacing,
200 info.xregistry.c_str(),
201 info.xencoding.c_str());
202
203 // get the list of all fonts
204 return XListFonts((Display *)wxGetDisplay(), pattern.mb_str(), 32767, nFonts);
205 }
206
207 static bool ProcessFamiliesFromFontList(wxFontEnumerator *This,
208 char **fonts,
209 int nFonts)
210 {
211 #if wxUSE_REGEX
212 wxRegEx re(wxT("^(-[^-]*){14}$"), wxRE_NOSUB);
213 #endif // wxUSE_REGEX
214
215 // extract the list of (unique) font families
216 wxSortedArrayString families;
217 for ( int n = 0; n < nFonts; n++ )
218 {
219 char *font = fonts[n];
220 #if wxUSE_REGEX
221 if ( !re.Matches(font) )
222 #else // !wxUSE_REGEX
223 if ( !wxString(font).Matches(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-*-*")) )
224 #endif // wxUSE_REGEX/!wxUSE_REGEX
225 {
226 // it's not a full font name (probably an alias)
227 continue;
228 }
229
230 // coverity[returned_null]
231 char *dash = strchr(font + 1, '-');
232 char *family = dash + 1;
233 dash = strchr(family, '-');
234 *dash = '\0'; // !NULL because Matches() above succeeded
235 wxString fam(family);
236
237 if ( families.Index(fam) == wxNOT_FOUND )
238 {
239 if ( !This->OnFacename(fam) )
240 {
241 // stop enumerating
242 return false;
243 }
244
245 families.Add(fam);
246 }
247 //else: already seen
248 }
249
250 return true;
251 }
252 #endif
253 // wxUSE_NANOX
254
255 // ----------------------------------------------------------------------------
256 // wxFontEnumerator
257 // ----------------------------------------------------------------------------
258
259 bool wxFontEnumerator::EnumerateFacenames(wxFontEncoding encoding,
260 bool fixedWidthOnly)
261 {
262 #if wxUSE_NANOX
263 return false;
264 #else
265 int nFonts;
266 char **fonts;
267
268 if ( fixedWidthOnly )
269 {
270 bool cont = true;
271 fonts = CreateFontList(wxT('m'), encoding, &nFonts);
272 if ( fonts )
273 {
274 cont = ProcessFamiliesFromFontList(this, fonts, nFonts);
275
276 XFreeFontNames(fonts);
277 }
278
279 if ( !cont )
280 {
281 return true;
282 }
283
284 fonts = CreateFontList(wxT('c'), encoding, &nFonts);
285 if ( !fonts )
286 {
287 return true;
288 }
289 }
290 else
291 {
292 fonts = CreateFontList(wxT('*'), encoding, &nFonts);
293
294 if ( !fonts )
295 {
296 // it's ok if there are no fonts in given encoding - but it's not
297 // ok if there are no fonts at all
298 wxASSERT_MSG(encoding != wxFONTENCODING_SYSTEM,
299 wxT("No fonts at all on this system?"));
300
301 return false;
302 }
303 }
304
305 (void)ProcessFamiliesFromFontList(this, fonts, nFonts);
306
307 XFreeFontNames(fonts);
308 return true;
309 #endif
310 // wxUSE_NANOX
311 }
312
313 bool wxFontEnumerator::EnumerateEncodings(const wxString& family)
314 {
315 #if wxUSE_NANOX
316 return false;
317 #else
318 wxString pattern;
319 pattern.Printf(wxT("-*-%s-*-*-*-*-*-*-*-*-*-*-*-*"),
320 family.empty() ? wxT("*") : family.c_str());
321
322 // get the list of all fonts
323 int nFonts;
324 char **fonts = XListFonts((Display *)wxGetDisplay(), pattern.mb_str(),
325 32767, &nFonts);
326
327 if ( !fonts )
328 {
329 // unknown family?
330 return false;
331 }
332
333 // extract the list of (unique) encodings
334 wxSortedArrayString encodings;
335 for ( int n = 0; n < nFonts; n++ )
336 {
337 char *font = fonts[n];
338 if ( !wxString(font).Matches(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-*-*")) )
339 {
340 // it's not a full font name (probably an alias)
341 continue;
342 }
343
344 // extract the family
345 char *dash = strchr(font + 1, '-');
346 char *familyFont = dash + 1;
347 dash = strchr(familyFont, '-');
348 *dash = '\0'; // !NULL because Matches() above succeeded
349
350 if ( !family.empty() && (family != familyFont) )
351 {
352 // family doesn't match
353 continue;
354 }
355
356 // now extract the registry/encoding
357 char *p = dash + 1; // just after the dash after family
358 dash = strrchr(p, '-');
359
360 wxString registry(dash + 1);
361 *dash = '\0';
362
363 dash = strrchr(p, '-');
364 wxString encoding(dash + 1);
365
366 encoding << wxT('-') << registry;
367 if ( encodings.Index(encoding) == wxNOT_FOUND )
368 {
369 if ( !OnFontEncoding(familyFont, encoding) )
370 {
371 break;
372 }
373
374 encodings.Add(encoding);
375 }
376 //else: already had this one
377 }
378
379 XFreeFontNames(fonts);
380
381 return true;
382 #endif
383 // wxUSE_NANOX
384 }
385
386 #endif // !wxUSE_PANGO