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: fontenum.cpp 43727 2006-12-01 10:14:28Z VS $
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"
47extern GtkWidget *wxGetRootWindow();
48#endif // __WXGTK20__
49
50extern "C" int wxCMPFUNC_CONV
51wxCompareFamilies (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
59bool 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
113bool wxFontEnumerator::EnumerateEncodings(const wxString& facename)
114{
115    return EnumerateEncodingsUTF8(facename);
116}
117
118
119#else // !wxUSE_PANGO
120
121#ifdef __VMS__ // Xlib.h for VMS is not (yet) compatible with C++
122               // The resulting warnings are switched off here
123#pragma message disable nosimpint
124#endif
125#include <X11/Xlib.h>
126#ifdef __VMS__
127#pragma message enable nosimpint
128#endif
129
130// ----------------------------------------------------------------------------
131// private functions
132// ----------------------------------------------------------------------------
133
134// create the list of all fonts with the given spacing and encoding
135static char **CreateFontList(wxChar spacing, wxFontEncoding encoding,
136                             int *nFonts);
137
138// extract all font families from the given font list and call our
139// OnFacename() for each of them
140static bool ProcessFamiliesFromFontList(wxFontEnumerator *This,
141                                        char **fonts,
142                                        int nFonts);
143
144
145// ----------------------------------------------------------------------------
146// private types
147// ----------------------------------------------------------------------------
148
149// ============================================================================
150// implementation
151// ============================================================================
152
153// ----------------------------------------------------------------------------
154// helpers
155// ----------------------------------------------------------------------------
156
157#if !wxUSE_NANOX
158static char **CreateFontList(wxChar spacing,
159                             wxFontEncoding encoding,
160                             int *nFonts)
161{
162    wxNativeEncodingInfo info;
163    wxGetNativeFontEncoding(encoding, &info);
164
165#if wxUSE_FONTMAP
166    if ( !wxTestFontEncoding(info) )
167    {
168        // ask font mapper for a replacement
169        (void)wxFontMapper::Get()->GetAltForEncoding(encoding, &info);
170    }
171#endif // wxUSE_FONTMAP
172
173    wxString pattern;
174    pattern.Printf(wxT("-*-*-*-*-*-*-*-*-*-*-%c-*-%s-%s"),
175                   spacing,
176                   info.xregistry.c_str(),
177                   info.xencoding.c_str());
178
179    // get the list of all fonts
180    return XListFonts((Display *)wxGetDisplay(), pattern.mb_str(), 32767, nFonts);
181}
182
183static bool ProcessFamiliesFromFontList(wxFontEnumerator *This,
184                                        char **fonts,
185                                        int nFonts)
186{
187#if wxUSE_REGEX
188    wxRegEx re(wxT("^(-[^-]*){14}$"), wxRE_NOSUB);
189#endif // wxUSE_REGEX
190
191    // extract the list of (unique) font families
192    wxSortedArrayString families;
193    for ( int n = 0; n < nFonts; n++ )
194    {
195        char *font = fonts[n];
196#if wxUSE_REGEX
197        if ( !re.Matches(font) )
198#else // !wxUSE_REGEX
199        if ( !wxString(font).Matches(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-*-*")) )
200#endif // wxUSE_REGEX/!wxUSE_REGEX
201        {
202            // it's not a full font name (probably an alias)
203            continue;
204        }
205
206        // coverity[returned_null]
207        char *dash = strchr(font + 1, '-');
208        char *family = dash + 1;
209        dash = strchr(family, '-');
210        *dash = '\0'; // !NULL because Matches() above succeeded
211        wxString fam(family);
212
213        if ( families.Index(fam) == wxNOT_FOUND )
214        {
215            if ( !This->OnFacename(fam) )
216            {
217                // stop enumerating
218                return false;
219            }
220
221            families.Add(fam);
222        }
223        //else: already seen
224    }
225
226    return true;
227}
228#endif
229  // wxUSE_NANOX
230
231// ----------------------------------------------------------------------------
232// wxFontEnumerator
233// ----------------------------------------------------------------------------
234
235bool wxFontEnumerator::EnumerateFacenames(wxFontEncoding encoding,
236                                          bool fixedWidthOnly)
237{
238#if wxUSE_NANOX
239    return false;
240#else
241    int nFonts;
242    char **fonts;
243
244    if ( fixedWidthOnly )
245    {
246        bool cont = true;
247        fonts = CreateFontList(wxT('m'), encoding, &nFonts);
248        if ( fonts )
249        {
250            cont = ProcessFamiliesFromFontList(this, fonts, nFonts);
251
252            XFreeFontNames(fonts);
253        }
254
255        if ( !cont )
256        {
257            return true;
258        }
259
260        fonts = CreateFontList(wxT('c'), encoding, &nFonts);
261        if ( !fonts )
262        {
263            return true;
264        }
265    }
266    else
267    {
268        fonts = CreateFontList(wxT('*'), encoding, &nFonts);
269
270        if ( !fonts )
271        {
272            // it's ok if there are no fonts in given encoding - but it's not
273            // ok if there are no fonts at all
274            wxASSERT_MSG(encoding != wxFONTENCODING_SYSTEM,
275                         wxT("No fonts at all on this system?"));
276
277            return false;
278        }
279    }
280
281    (void)ProcessFamiliesFromFontList(this, fonts, nFonts);
282
283    XFreeFontNames(fonts);
284    return true;
285#endif
286    // wxUSE_NANOX
287}
288
289bool wxFontEnumerator::EnumerateEncodings(const wxString& family)
290{
291#if wxUSE_NANOX
292    return false;
293#else
294    wxString pattern;
295    pattern.Printf(wxT("-*-%s-*-*-*-*-*-*-*-*-*-*-*-*"),
296                   family.empty() ? wxT("*") : family.c_str());
297
298    // get the list of all fonts
299    int nFonts;
300    char **fonts = XListFonts((Display *)wxGetDisplay(), pattern.mb_str(),
301                              32767, &nFonts);
302
303    if ( !fonts )
304    {
305        // unknown family?
306        return false;
307    }
308
309    // extract the list of (unique) encodings
310    wxSortedArrayString encodings;
311    for ( int n = 0; n < nFonts; n++ )
312    {
313        char *font = fonts[n];
314        if ( !wxString(font).Matches(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-*-*")) )
315        {
316            // it's not a full font name (probably an alias)
317            continue;
318        }
319
320        // extract the family
321        char *dash = strchr(font + 1, '-');
322        char *familyFont = dash + 1;
323        dash = strchr(familyFont, '-');
324        *dash = '\0'; // !NULL because Matches() above succeeded
325
326        if ( !family.empty() && (family != familyFont) )
327        {
328            // family doesn't match
329            continue;
330        }
331
332        // now extract the registry/encoding
333        char *p = dash + 1; // just after the dash after family
334        dash = strrchr(p, '-');
335
336        wxString registry(dash + 1);
337        *dash = '\0';
338
339        dash = strrchr(p, '-');
340        wxString encoding(dash + 1);
341
342        encoding << wxT('-') << registry;
343        if ( encodings.Index(encoding) == wxNOT_FOUND )
344        {
345            if ( !OnFontEncoding(familyFont, encoding) )
346            {
347                break;
348            }
349
350            encodings.Add(encoding);
351        }
352        //else: already had this one
353    }
354
355    XFreeFontNames(fonts);
356
357    return true;
358#endif
359    // wxUSE_NANOX
360}
361
362#endif // !wxUSE_PANGO
363