]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unix/gtkfont.c
Work around OS X GTK treating Option as an AltGr key.
[PuTTY.git] / unix / gtkfont.c
1 /*
2  * Unified font management for GTK.
3  * 
4  * PuTTY is willing to use both old-style X server-side bitmap
5  * fonts _and_ GTK2/Pango client-side fonts. This requires us to
6  * do a bit of work to wrap the two wildly different APIs into
7  * forms the rest of the code can switch between seamlessly, and
8  * also requires a custom font selector capable of handling both
9  * types of font.
10  */
11
12 #include <assert.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include <gtk/gtk.h>
17 #if !GTK_CHECK_VERSION(3,0,0)
18 #include <gdk/gdkkeysyms.h>
19 #endif
20
21 #define MAY_REFER_TO_GTK_IN_HEADERS
22
23 #include "putty.h"
24 #include "gtkfont.h"
25 #include "gtkcompat.h"
26 #include "gtkmisc.h"
27 #include "tree234.h"
28
29 #ifndef NOT_X_WINDOWS
30 #include <gdk/gdkx.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/Xatom.h>
34 #endif
35
36 /*
37  * Future work:
38  * 
39  *  - it would be nice to have a display of the current font name,
40  *    and in particular whether it's client- or server-side,
41  *    during the progress of the font selector.
42  */
43
44 #if !GLIB_CHECK_VERSION(1,3,7)
45 #define g_ascii_strcasecmp g_strcasecmp
46 #define g_ascii_strncasecmp g_strncasecmp
47 #endif
48
49 /*
50  * Ad-hoc vtable mechanism to allow font structures to be
51  * polymorphic.
52  * 
53  * Any instance of `unifont' used in the vtable functions will
54  * actually be the first element of a larger structure containing
55  * data specific to the subtype. This is permitted by the ISO C
56  * provision that one may safely cast between a pointer to a
57  * structure and a pointer to its first element.
58  */
59
60 #define FONTFLAG_CLIENTSIDE    0x0001
61 #define FONTFLAG_SERVERSIDE    0x0002
62 #define FONTFLAG_SERVERALIAS   0x0004
63 #define FONTFLAG_NONMONOSPACED 0x0008
64
65 #define FONTFLAG_SORT_MASK     0x0007 /* used to disambiguate font families */
66
67 typedef void (*fontsel_add_entry)(void *ctx, const char *realfontname,
68                                   const char *family, const char *charset,
69                                   const char *style, const char *stylekey,
70                                   int size, int flags,
71                                   const struct unifont_vtable *fontclass);
72
73 struct unifont_vtable {
74     /*
75      * `Methods' of the `class'.
76      */
77     unifont *(*create)(GtkWidget *widget, const char *name, int wide, int bold,
78                        int shadowoffset, int shadowalways);
79     unifont *(*create_fallback)(GtkWidget *widget, int height, int wide,
80                                 int bold, int shadowoffset, int shadowalways);
81     void (*destroy)(unifont *font);
82     int (*has_glyph)(unifont *font, wchar_t glyph);
83     void (*draw_text)(unifont_drawctx *ctx, unifont *font,
84                       int x, int y, const wchar_t *string, int len,
85                       int wide, int bold, int cellwidth);
86     void (*enum_fonts)(GtkWidget *widget,
87                        fontsel_add_entry callback, void *callback_ctx);
88     char *(*canonify_fontname)(GtkWidget *widget, const char *name, int *size,
89                                int *flags, int resolve_aliases);
90     char *(*scale_fontname)(GtkWidget *widget, const char *name, int size);
91
92     /*
93      * `Static data members' of the `class'.
94      */
95     const char *prefix;
96 };
97
98 #ifndef NOT_X_WINDOWS
99
100 /* ----------------------------------------------------------------------
101  * X11 font implementation, directly using Xlib calls. Conditioned out
102  * if X11 fonts aren't available at all (e.g. building with GTK3 for a
103  * back end other than X).
104  */
105
106 static int x11font_has_glyph(unifont *font, wchar_t glyph);
107 static void x11font_draw_text(unifont_drawctx *ctx, unifont *font,
108                               int x, int y, const wchar_t *string, int len,
109                               int wide, int bold, int cellwidth);
110 static unifont *x11font_create(GtkWidget *widget, const char *name,
111                                int wide, int bold,
112                                int shadowoffset, int shadowalways);
113 static void x11font_destroy(unifont *font);
114 static void x11font_enum_fonts(GtkWidget *widget,
115                                fontsel_add_entry callback, void *callback_ctx);
116 static char *x11font_canonify_fontname(GtkWidget *widget, const char *name,
117                                        int *size, int *flags,
118                                        int resolve_aliases);
119 static char *x11font_scale_fontname(GtkWidget *widget, const char *name,
120                                     int size);
121
122 #ifdef DRAW_TEXT_CAIRO
123 struct cairo_cached_glyph {
124     cairo_surface_t *surface;
125     unsigned char *bitmap;
126 };
127 #endif
128
129 /*
130  * Structure storing a single physical XFontStruct, plus associated
131  * data.
132  */
133 typedef struct x11font_individual {
134     /* The XFontStruct itself. */
135     XFontStruct *xfs;
136
137     /*
138      * The `allocated' flag indicates whether we've tried to fetch
139      * this subfont already (thus distinguishing xfs==NULL because we
140      * haven't tried yet from xfs==NULL because we tried and failed,
141      * so that we don't keep trying and failing subsequently).
142      */
143     int allocated;
144
145 #ifdef DRAW_TEXT_CAIRO
146     /*
147      * A cache of glyph bitmaps downloaded from the X server when
148      * we're in Cairo rendering mode. If glyphcache itself is
149      * non-NULL, then entries in [0,nglyphs) are expected to be
150      * initialised to either NULL or a bitmap pointer.
151      */
152     struct cairo_cached_glyph *glyphcache;
153     int nglyphs;
154
155     /*
156      * X server paraphernalia for actually downloading the glyphs.
157      */
158     Pixmap pixmap;
159     GC gc;
160     int pixwidth, pixheight, pixoriginx, pixoriginy;
161
162     /*
163      * Paraphernalia for loading the resulting bitmaps into Cairo.
164      */
165     int rowsize, allsize, indexflip;
166 #endif
167
168 } x11font_individual;
169
170 struct x11font {
171     struct unifont u;
172     /*
173      * Individual physical X fonts. We store a number of these, for
174      * automatically guessed bold and wide variants.
175      */
176     x11font_individual fonts[4];
177     /*
178      * `sixteen_bit' is true iff the font object is indexed by
179      * values larger than a byte. That is, this flag tells us
180      * whether we use XDrawString or XDrawString16, etc.
181      */
182     int sixteen_bit;
183     /*
184      * `variable' is true iff the font is non-fixed-pitch. This
185      * enables some code which takes greater care over character
186      * positioning during text drawing.
187      */
188     int variable;
189     /*
190      * real_charset is the charset used when translating text into the
191      * font's internal encoding inside draw_text(). This need not be
192      * the same as the public_charset provided to the client; for
193      * example, public_charset might be CS_ISO8859_1 while
194      * real_charset is CS_ISO8859_1_X11.
195      */
196     int real_charset;
197     /*
198      * Data passed in to unifont_create().
199      */
200     int wide, bold, shadowoffset, shadowalways;
201 };
202
203 static const struct unifont_vtable x11font_vtable = {
204     x11font_create,
205     NULL,                              /* no fallback fonts in X11 */
206     x11font_destroy,
207     x11font_has_glyph,
208     x11font_draw_text,
209     x11font_enum_fonts,
210     x11font_canonify_fontname,
211     x11font_scale_fontname,
212     "server",
213 };
214
215 static char *x11_guess_derived_font_name(XFontStruct *xfs, int bold, int wide)
216 {
217     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
218     Atom fontprop = XInternAtom(disp, "FONT", False);
219     unsigned long ret;
220     if (XGetFontProperty(xfs, fontprop, &ret)) {
221         char *name = XGetAtomName(disp, (Atom)ret);
222         if (name && name[0] == '-') {
223             const char *strings[13];
224             char *dupname, *extrafree = NULL, *ret;
225             char *p, *q;
226             int nstr;
227
228             p = q = dupname = dupstr(name); /* skip initial minus */
229             nstr = 0;
230
231             while (*p && nstr < lenof(strings)) {
232                 if (*p == '-') {
233                     *p = '\0';
234                     strings[nstr++] = p+1;
235                 }
236                 p++;
237             }
238
239             if (nstr < lenof(strings)) {
240                 sfree(dupname);
241                 return NULL;           /* XLFD was malformed */
242             }
243
244             if (bold)
245                 strings[2] = "bold";
246
247             if (wide) {
248                 /* 4 is `wideness', which obviously may have changed. */
249                 /* 5 is additional style, which may be e.g. `ja' or `ko'. */
250                 strings[4] = strings[5] = "*";
251                 strings[11] = extrafree = dupprintf("%d", 2*atoi(strings[11]));
252             }
253
254             ret = dupcat("-", strings[ 0], "-", strings[ 1], "-", strings[ 2],
255                          "-", strings[ 3], "-", strings[ 4], "-", strings[ 5],
256                          "-", strings[ 6], "-", strings[ 7], "-", strings[ 8],
257                          "-", strings[ 9], "-", strings[10], "-", strings[11],
258                          "-", strings[12], NULL);
259             sfree(extrafree);
260             sfree(dupname);
261
262             return ret;
263         }
264     }
265     return NULL;
266 }
267
268 static int x11_font_width(XFontStruct *xfs, int sixteen_bit)
269 {
270     if (sixteen_bit) {
271         XChar2b space;
272         space.byte1 = 0;
273         space.byte2 = '0';
274         return XTextWidth16(xfs, &space, 1);
275     } else {
276         return XTextWidth(xfs, "0", 1);
277     }
278 }
279
280 static int x11_font_has_glyph(XFontStruct *xfs, int byte1, int byte2)
281 {
282     int index;
283
284     /*
285      * Not to be confused with x11font_has_glyph, which is a method of
286      * the x11font 'class' and hence takes a unifont as argument. This
287      * is the low-level function which grubs about in an actual
288      * XFontStruct to see if a given glyph exists.
289      *
290      * We must do this ourselves rather than letting Xlib's
291      * XTextExtents16 do the job, because XTextExtents will helpfully
292      * substitute the font's default_char for any missing glyph and
293      * not tell us it did so, which precisely won't help us find out
294      * which glyphs _are_ missing.
295      *
296      * The man page for XQueryFont is rather confusing about how the
297      * per_char array in the XFontStruct is laid out, because it gives
298      * formulae for determining the two-byte X character code _from_
299      * an index into the per_char array. Going the other way, it's
300      * rather simpler:
301      *
302      * The valid character codes have byte1 between min_byte1 and
303      * max_byte1 inclusive, and byte2 between min_char_or_byte2 and
304      * max_char_or_byte2 inclusive. This gives a rectangle of size
305      * (max_byte2-min_byte1+1) by
306      * (max_char_or_byte2-min_char_or_byte2+1), which is precisely the
307      * rectangle encoded in the per_char array. Hence, given a
308      * character code which is valid in the sense that it falls
309      * somewhere in that rectangle, its index in per_char is given by
310      * setting
311      *
312      *   x = byte2 - min_char_or_byte2
313      *   y = byte1 - min_byte1
314      *   index = y * (max_char_or_byte2-min_char_or_byte2+1) + x
315      *
316      * If min_byte1 and min_byte2 are both zero, that's a special case
317      * which can be treated as if min_byte2 was 1 instead, i.e. the
318      * per_char array just runs from min_char_or_byte2 to
319      * max_char_or_byte2 inclusive, and byte1 should always be zero.
320      */
321
322     if (byte2 < xfs->min_char_or_byte2 || byte2 > xfs->max_char_or_byte2)
323         return FALSE;
324
325     if (xfs->min_byte1 == 0 && xfs->max_byte1 == 0) {
326         index = byte2 - xfs->min_char_or_byte2;
327     } else {
328         if (byte1 < xfs->min_byte1 || byte1 > xfs->max_byte1)
329             return FALSE;
330         index = ((byte2 - xfs->min_char_or_byte2) +
331                  ((byte1 - xfs->min_byte1) *
332                   (xfs->max_char_or_byte2 - xfs->min_char_or_byte2 + 1)));
333     }
334
335     if (!xfs->per_char)   /* per_char NULL => everything in range exists */
336         return TRUE;
337
338     return (xfs->per_char[index].ascent + xfs->per_char[index].descent > 0 ||
339             xfs->per_char[index].width > 0);
340 }
341
342 static unifont *x11font_create(GtkWidget *widget, const char *name,
343                                int wide, int bold,
344                                int shadowoffset, int shadowalways)
345 {
346     struct x11font *xfont;
347     XFontStruct *xfs;
348     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
349     Atom charset_registry, charset_encoding, spacing;
350     unsigned long registry_ret, encoding_ret, spacing_ret;
351     int pubcs, realcs, sixteen_bit, variable;
352     int i;
353
354     xfs = XLoadQueryFont(disp, name);
355     if (!xfs)
356         return NULL;
357
358     charset_registry = XInternAtom(disp, "CHARSET_REGISTRY", False);
359     charset_encoding = XInternAtom(disp, "CHARSET_ENCODING", False);
360
361     pubcs = realcs = CS_NONE;
362     sixteen_bit = FALSE;
363     variable = TRUE;
364
365     if (XGetFontProperty(xfs, charset_registry, &registry_ret) &&
366         XGetFontProperty(xfs, charset_encoding, &encoding_ret)) {
367         char *reg, *enc;
368         reg = XGetAtomName(disp, (Atom)registry_ret);
369         enc = XGetAtomName(disp, (Atom)encoding_ret);
370         if (reg && enc) {
371             char *encoding = dupcat(reg, "-", enc, NULL);
372             pubcs = realcs = charset_from_xenc(encoding);
373
374             /*
375              * iso10646-1 is the only wide font encoding we
376              * support. In this case, we expect clients to give us
377              * UTF-8, which this module must internally convert
378              * into 16-bit Unicode.
379              */
380             if (!strcasecmp(encoding, "iso10646-1")) {
381                 sixteen_bit = TRUE;
382                 pubcs = realcs = CS_UTF8;
383             }
384
385             /*
386              * Hack for X line-drawing characters: if the primary font
387              * is encoded as ISO-8859-1, and has valid glyphs in the
388              * low character positions, it is assumed that those
389              * glyphs are the VT100 line-drawing character set.
390              */
391             if (pubcs == CS_ISO8859_1) {
392                 int ch;
393                 for (ch = 1; ch < 32; ch++)
394                     if (!x11_font_has_glyph(xfs, 0, ch))
395                         break;
396                 if (ch == 32)
397                     realcs = CS_ISO8859_1_X11;
398             }
399
400             sfree(encoding);
401         }
402     }
403
404     spacing = XInternAtom(disp, "SPACING", False);
405     if (XGetFontProperty(xfs, spacing, &spacing_ret)) {
406         char *spc;
407         spc = XGetAtomName(disp, (Atom)spacing_ret);
408
409         if (spc && strchr("CcMm", spc[0]))
410             variable = FALSE;
411     }
412
413     xfont = snew(struct x11font);
414     xfont->u.vt = &x11font_vtable;
415     xfont->u.width = x11_font_width(xfs, sixteen_bit);
416     xfont->u.ascent = xfs->ascent;
417     xfont->u.descent = xfs->descent;
418     xfont->u.height = xfont->u.ascent + xfont->u.descent;
419     xfont->u.public_charset = pubcs;
420     xfont->u.want_fallback = TRUE;
421 #ifdef DRAW_TEXT_GDK
422     xfont->u.preferred_drawtype = DRAWTYPE_GDK;
423 #elif defined DRAW_TEXT_CAIRO
424     xfont->u.preferred_drawtype = DRAWTYPE_CAIRO;
425 #else
426 #error No drawtype available at all
427 #endif
428     xfont->real_charset = realcs;
429     xfont->sixteen_bit = sixteen_bit;
430     xfont->variable = variable;
431     xfont->wide = wide;
432     xfont->bold = bold;
433     xfont->shadowoffset = shadowoffset;
434     xfont->shadowalways = shadowalways;
435
436     for (i = 0; i < lenof(xfont->fonts); i++) {
437         xfont->fonts[i].xfs = NULL;
438         xfont->fonts[i].allocated = FALSE;
439 #ifdef DRAW_TEXT_CAIRO
440         xfont->fonts[i].glyphcache = NULL;
441         xfont->fonts[i].nglyphs = 0;
442         xfont->fonts[i].pixmap = None;
443         xfont->fonts[i].gc = None;
444 #endif
445     }
446     xfont->fonts[0].xfs = xfs;
447     xfont->fonts[0].allocated = TRUE;
448
449     return (unifont *)xfont;
450 }
451
452 static void x11font_destroy(unifont *font)
453 {
454     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
455     struct x11font *xfont = (struct x11font *)font;
456     int i;
457
458     for (i = 0; i < lenof(xfont->fonts); i++) {
459         if (xfont->fonts[i].xfs)
460             XFreeFont(disp, xfont->fonts[i].xfs);
461 #ifdef DRAW_TEXT_CAIRO
462         if (xfont->fonts[i].gc != None)
463             XFreeGC(disp, xfont->fonts[i].gc);
464         if (xfont->fonts[i].pixmap != None)
465             XFreePixmap(disp, xfont->fonts[i].pixmap);
466         if (xfont->fonts[i].glyphcache) {
467             int j;
468             for (j = 0; j < xfont->fonts[i].nglyphs; j++) {
469                 cairo_surface_destroy(xfont->fonts[i].glyphcache[j].surface);
470                 sfree(xfont->fonts[i].glyphcache[j].bitmap);
471             }
472             sfree(xfont->fonts[i].glyphcache);
473         }
474 #endif
475     }
476     sfree(font);
477 }
478
479 static void x11_alloc_subfont(struct x11font *xfont, int sfid)
480 {
481     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
482     char *derived_name = x11_guess_derived_font_name
483         (xfont->fonts[0].xfs, sfid & 1, !!(sfid & 2));
484     xfont->fonts[sfid].xfs = XLoadQueryFont(disp, derived_name);
485     xfont->fonts[sfid].allocated = TRUE;
486     sfree(derived_name);
487     /* Note that xfont->fonts[sfid].xfs may still be NULL, if XLQF failed. */
488 }
489
490 static int x11font_has_glyph(unifont *font, wchar_t glyph)
491 {
492     struct x11font *xfont = (struct x11font *)font;
493
494     if (xfont->sixteen_bit) {
495         /*
496          * This X font has 16-bit character indices, which means
497          * we can directly use our Unicode input value.
498          */
499         return x11_font_has_glyph(xfont->fonts[0].xfs,
500                                   glyph >> 8, glyph & 0xFF);
501     } else {
502         /*
503          * This X font has 8-bit indices, so we must convert to the
504          * appropriate character set.
505          */
506         char sbstring[2];
507         int sblen = wc_to_mb(xfont->real_charset, 0, &glyph, 1,
508                              sbstring, 2, "", NULL, NULL);
509         if (sblen == 0 || !sbstring[0])
510             return FALSE;              /* not even in the charset */
511
512         return x11_font_has_glyph(xfont->fonts[0].xfs, 0,
513                                   (unsigned char)sbstring[0]);
514     }
515 }
516
517 #if !GTK_CHECK_VERSION(2,0,0)
518 #define GDK_DRAWABLE_XID(d) GDK_WINDOW_XWINDOW(d) /* GTK1's name for this */
519 #elif GTK_CHECK_VERSION(3,0,0)
520 #define GDK_DRAWABLE_XID(d) GDK_WINDOW_XID(d) /* GTK3's name for this */
521 #endif
522
523 static int x11font_width_16(unifont_drawctx *ctx, x11font_individual *xfi,
524                             const void *vstring, int start, int length)
525 {
526     const XChar2b *string = (const XChar2b *)vstring;
527     return XTextWidth16(xfi->xfs, string+start, length);
528 }
529
530 static int x11font_width_8(unifont_drawctx *ctx, x11font_individual *xfi,
531                            const void *vstring, int start, int length)
532 {
533     const char *string = (const char *)vstring;
534     return XTextWidth(xfi->xfs, string+start, length);
535 }
536
537 #ifdef DRAW_TEXT_GDK
538 static void x11font_gdk_setup(unifont_drawctx *ctx, x11font_individual *xfi)
539 {
540     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
541     XSetFont(disp, GDK_GC_XGC(ctx->u.gdk.gc), xfi->xfs->fid);
542 }
543
544 static void x11font_gdk_draw_16(unifont_drawctx *ctx,
545                                 x11font_individual *xfi, int x, int y,
546                                 const void *vstring, int start, int length)
547 {
548     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
549     const XChar2b *string = (const XChar2b *)vstring;
550     XDrawString16(disp, GDK_DRAWABLE_XID(ctx->u.gdk.target),
551                   GDK_GC_XGC(ctx->u.gdk.gc), x, y, string+start, length);
552 }
553
554 static void x11font_gdk_draw_8(unifont_drawctx *ctx,
555                                x11font_individual *xfi, int x, int y,
556                                const void *vstring, int start, int length)
557 {
558     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
559     const char *string = (const char *)vstring;
560     XDrawString(disp, GDK_DRAWABLE_XID(ctx->u.gdk.target),
561                 GDK_GC_XGC(ctx->u.gdk.gc), x, y, string+start, length);
562 }
563 #endif
564
565 #ifdef DRAW_TEXT_CAIRO
566 static void x11font_cairo_setup(unifont_drawctx *ctx, x11font_individual *xfi)
567 {
568     if (xfi->pixmap == None) {
569         Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
570         XGCValues gcvals;
571         GdkWindow *widgetwin = gtk_widget_get_window(ctx->u.cairo.widget);
572         int widgetscr = GDK_SCREEN_XNUMBER(gdk_window_get_screen(widgetwin));
573
574         xfi->pixwidth =
575             xfi->xfs->max_bounds.rbearing - xfi->xfs->min_bounds.lbearing;
576         xfi->pixheight =
577             xfi->xfs->max_bounds.ascent + xfi->xfs->max_bounds.descent;
578         xfi->pixoriginx = -xfi->xfs->min_bounds.lbearing;
579         xfi->pixoriginy = xfi->xfs->max_bounds.ascent;
580
581         xfi->rowsize = cairo_format_stride_for_width(CAIRO_FORMAT_A1,
582                                                      xfi->pixwidth);
583         xfi->allsize = xfi->rowsize * xfi->pixheight;
584
585         {
586             /*
587              * Test host endianness and use it to set xfi->indexflip,
588              * which is XORed into our left-shift counts in order to
589              * implement the CAIRO_FORMAT_A1 specification, in which
590              * each bitmap byte is oriented LSB-first on little-endian
591              * platforms and MSB-first on big-endian ones.
592              *
593              * This is the same technique Cairo itself uses to test
594              * endianness, so hopefully it'll work in any situation
595              * where Cairo is usable at all.
596              */
597             static const int endianness_test = 1;
598             xfi->indexflip = (*((char *) &endianness_test) == 1) ? 0 : 7;
599         }
600
601         xfi->pixmap = XCreatePixmap
602             (disp,
603              GDK_DRAWABLE_XID(gtk_widget_get_window(ctx->u.cairo.widget)),
604              xfi->pixwidth, xfi->pixheight, 1);
605         gcvals.foreground = WhitePixel(disp, widgetscr);
606         gcvals.background = BlackPixel(disp, widgetscr);
607         gcvals.font = xfi->xfs->fid;
608         xfi->gc = XCreateGC(disp, xfi->pixmap,
609                             GCForeground | GCBackground | GCFont, &gcvals);
610     }
611 }
612
613 static void x11font_cairo_cache_glyph(x11font_individual *xfi, int glyphindex)
614 {
615     XImage *image;
616     int x, y;
617     unsigned char *bitmap;
618     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
619
620     bitmap = snewn(xfi->allsize, unsigned char);
621     memset(bitmap, 0, xfi->allsize);
622
623     image = XGetImage(disp, xfi->pixmap, 0, 0,
624                       xfi->pixwidth, xfi->pixheight, AllPlanes, XYPixmap);
625     for (y = 0; y < xfi->pixheight; y++) {
626         for (x = 0; x < xfi->pixwidth; x++) {
627             unsigned long pixel = XGetPixel(image, x, y);
628             if (pixel) {
629                 int byteindex = y * xfi->rowsize + x/8;
630                 int bitindex = (x & 7) ^ xfi->indexflip;
631                 bitmap[byteindex] |= 1U << bitindex;
632             }
633         }
634     }
635     XDestroyImage(image);
636
637     if (xfi->nglyphs <= glyphindex) {
638         /* Round up to the next multiple of 256 on the general
639          * principle that Unicode characters come in contiguous blocks
640          * often used together */
641         int old_nglyphs = xfi->nglyphs;
642         xfi->nglyphs = (glyphindex + 0x100) & ~0xFF;
643         xfi->glyphcache = sresize(xfi->glyphcache, xfi->nglyphs,
644                                   struct cairo_cached_glyph);
645
646         while (old_nglyphs < xfi->nglyphs) {
647             xfi->glyphcache[old_nglyphs].surface = NULL;
648             xfi->glyphcache[old_nglyphs].bitmap = NULL;
649             old_nglyphs++;
650         }
651     }
652     xfi->glyphcache[glyphindex].bitmap = bitmap;
653     xfi->glyphcache[glyphindex].surface = cairo_image_surface_create_for_data
654         (bitmap, CAIRO_FORMAT_A1, xfi->pixwidth, xfi->pixheight, xfi->rowsize);
655 }
656
657 static void x11font_cairo_draw_glyph(unifont_drawctx *ctx,
658                                      x11font_individual *xfi, int x, int y,
659                                      int glyphindex)
660 {
661     if (xfi->glyphcache[glyphindex].surface) {
662         cairo_mask_surface(ctx->u.cairo.cr,
663                            xfi->glyphcache[glyphindex].surface,
664                            x - xfi->pixoriginx, y - xfi->pixoriginy);
665     }
666 }
667
668 static void x11font_cairo_draw_16(unifont_drawctx *ctx,
669                                   x11font_individual *xfi, int x, int y,
670                                   const void *vstring, int start, int length)
671 {
672     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
673     const XChar2b *string = (const XChar2b *)vstring + start;
674     int i;
675     for (i = 0; i < length; i++) {
676         if (x11_font_has_glyph(xfi->xfs, string[i].byte1, string[i].byte2)) {
677             int glyphindex = (256 * (unsigned char)string[i].byte1 +
678                               (unsigned char)string[i].byte2);
679             if (glyphindex >= xfi->nglyphs ||
680                 !xfi->glyphcache[glyphindex].surface) {
681                 XDrawImageString16(disp, xfi->pixmap, xfi->gc,
682                                    xfi->pixoriginx, xfi->pixoriginy,
683                                    string+i, 1);
684                 x11font_cairo_cache_glyph(xfi, glyphindex);
685             }
686             x11font_cairo_draw_glyph(ctx, xfi, x, y, glyphindex);
687             x += XTextWidth16(xfi->xfs, string+i, 1);
688         }
689     }
690 }
691
692 static void x11font_cairo_draw_8(unifont_drawctx *ctx,
693                                  x11font_individual *xfi, int x, int y,
694                                  const void *vstring, int start, int length)
695 {
696     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
697     const char *string = (const char *)vstring + start;
698     int i;
699     for (i = 0; i < length; i++) {
700         if (x11_font_has_glyph(xfi->xfs, 0, string[i])) {
701             int glyphindex = (unsigned char)string[i];
702             if (glyphindex >= xfi->nglyphs ||
703                 !xfi->glyphcache[glyphindex].surface) {
704                 XDrawImageString(disp, xfi->pixmap, xfi->gc,
705                                  xfi->pixoriginx, xfi->pixoriginy,
706                                  string+i, 1);
707                 x11font_cairo_cache_glyph(xfi, glyphindex);
708             }
709             x11font_cairo_draw_glyph(ctx, xfi, x, y, glyphindex);
710             x += XTextWidth(xfi->xfs, string+i, 1);
711         }
712     }
713 }
714 #endif /* DRAW_TEXT_CAIRO */
715
716 struct x11font_drawfuncs {
717     int (*width)(unifont_drawctx *ctx, x11font_individual *xfi,
718                  const void *vstring, int start, int length);
719     void (*setup)(unifont_drawctx *ctx, x11font_individual *xfi);
720     void (*draw)(unifont_drawctx *ctx, x11font_individual *xfi, int x, int y,
721                  const void *vstring, int start, int length);
722 };
723
724 /*
725  * This array has two entries per compiled-in drawtype; of each pair,
726  * the first is for an 8-bit font and the second for 16-bit.
727  */
728 static const struct x11font_drawfuncs x11font_drawfuncs[2*DRAWTYPE_NTYPES] = {
729 #ifdef DRAW_TEXT_GDK
730     /* gdk, 8-bit */
731     {
732         x11font_width_8,
733         x11font_gdk_setup,
734         x11font_gdk_draw_8,
735     },
736     /* gdk, 16-bit */
737     {
738         x11font_width_16,
739         x11font_gdk_setup,
740         x11font_gdk_draw_16,
741     },
742 #endif
743 #ifdef DRAW_TEXT_CAIRO
744     /* cairo, 8-bit */
745     {
746         x11font_width_8,
747         x11font_cairo_setup,
748         x11font_cairo_draw_8,
749     },
750     /* [3] cairo, 16-bit */
751     {
752         x11font_width_16,
753         x11font_cairo_setup,
754         x11font_cairo_draw_16,
755     },
756 #endif
757 };
758
759 static void x11font_really_draw_text(const struct x11font_drawfuncs *dfns,
760                                      unifont_drawctx *ctx,
761                                      x11font_individual *xfi, int x, int y,
762                                      const void *string, int nchars,
763                                      int shadowoffset,
764                                      int fontvariable, int cellwidth)
765 {
766     int start = 0, step, nsteps, centre;
767
768     if (fontvariable) {
769         /*
770          * In a variable-pitch font, we draw one character at a
771          * time, and centre it in the character cell.
772          */
773         step = 1;
774         nsteps = nchars;
775         centre = TRUE;
776     } else {
777         /*
778          * In a fixed-pitch font, we can draw the whole lot in one go.
779          */
780         step = nchars;
781         nsteps = 1;
782         centre = FALSE;
783     }
784
785     dfns->setup(ctx, xfi);
786
787     while (nsteps-- > 0) {
788         int X = x;
789         if (centre)
790             X += (cellwidth - dfns->width(ctx, xfi, string, start, step)) / 2;
791
792         dfns->draw(ctx, xfi, X, y, string, start, step);
793         if (shadowoffset)
794             dfns->draw(ctx, xfi, X + shadowoffset, y, string, start, step);
795
796         x += cellwidth;
797         start += step;
798     }
799 }
800
801 static void x11font_draw_text(unifont_drawctx *ctx, unifont *font,
802                               int x, int y, const wchar_t *string, int len,
803                               int wide, int bold, int cellwidth)
804 {
805     struct x11font *xfont = (struct x11font *)font;
806     int sfid;
807     int shadowoffset = 0;
808     int mult = (wide ? 2 : 1);
809     int index = 2 * (int)ctx->type;
810
811     wide -= xfont->wide;
812     bold -= xfont->bold;
813
814     /*
815      * Decide which subfont we're using, and whether we have to
816      * use shadow bold.
817      */
818     if (xfont->shadowalways && bold) {
819         shadowoffset = xfont->shadowoffset;
820         bold = 0;
821     }
822     sfid = 2 * wide + bold;
823     if (!xfont->fonts[sfid].allocated)
824         x11_alloc_subfont(xfont, sfid);
825     if (bold && !xfont->fonts[sfid].xfs) {
826         bold = 0;
827         shadowoffset = xfont->shadowoffset;
828         sfid = 2 * wide + bold;
829         if (!xfont->fonts[sfid].allocated)
830             x11_alloc_subfont(xfont, sfid);
831     }
832
833     if (!xfont->fonts[sfid].xfs)
834         return;                        /* we've tried our best, but no luck */
835
836     if (xfont->sixteen_bit) {
837         /*
838          * This X font has 16-bit character indices, which means
839          * we can directly use our Unicode input string.
840          */
841         XChar2b *xcs;
842         int i;
843
844         xcs = snewn(len, XChar2b);
845         for (i = 0; i < len; i++) {
846             xcs[i].byte1 = string[i] >> 8;
847             xcs[i].byte2 = string[i];
848         }
849
850         x11font_really_draw_text(x11font_drawfuncs + index + 1, ctx,
851                                  &xfont->fonts[sfid], x, y,
852                                  xcs, len, shadowoffset,
853                                  xfont->variable, cellwidth * mult);
854         sfree(xcs);
855     } else {
856         /*
857          * This X font has 8-bit indices, so we must convert to the
858          * appropriate character set.
859          */
860         char *sbstring = snewn(len+1, char);
861         int sblen = wc_to_mb(xfont->real_charset, 0, string, len,
862                              sbstring, len+1, ".", NULL, NULL);
863         x11font_really_draw_text(x11font_drawfuncs + index + 0, ctx,
864                                  &xfont->fonts[sfid], x, y,
865                                  sbstring, sblen, shadowoffset,
866                                  xfont->variable, cellwidth * mult);
867         sfree(sbstring);
868     }
869 }
870
871 static void x11font_enum_fonts(GtkWidget *widget,
872                                fontsel_add_entry callback, void *callback_ctx)
873 {
874     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
875     char **fontnames;
876     char *tmp = NULL;
877     int nnames, i, max, tmpsize;
878
879     max = 32768;
880     while (1) {
881         fontnames = XListFonts(disp, "*", max, &nnames);
882         if (nnames >= max) {
883             XFreeFontNames(fontnames);
884             max *= 2;
885         } else
886             break;
887     }
888
889     tmpsize = 0;
890
891     for (i = 0; i < nnames; i++) {
892         if (fontnames[i][0] == '-') {
893             /*
894              * Dismember an XLFD and convert it into the format
895              * we'll be using in the font selector.
896              */
897             char *components[14];
898             char *p, *font, *style, *stylekey, *charset;
899             int j, weightkey, slantkey, setwidthkey;
900             int thistmpsize, fontsize, flags;
901
902             thistmpsize = 4 * strlen(fontnames[i]) + 256;
903             if (tmpsize < thistmpsize) {
904                 tmpsize = thistmpsize;
905                 tmp = sresize(tmp, tmpsize, char);
906             }
907             strcpy(tmp, fontnames[i]);
908
909             p = tmp;
910             for (j = 0; j < 14; j++) {
911                 if (*p)
912                     *p++ = '\0';
913                 components[j] = p;
914                 while (*p && *p != '-')
915                     p++;
916             }
917             *p++ = '\0';
918
919             /*
920              * Font name is made up of fields 0 and 1, in reverse
921              * order with parentheses. (This is what the GTK 1.2 X
922              * font selector does, and it seems to come out
923              * looking reasonably sensible.)
924              */
925             font = p;
926             p += 1 + sprintf(p, "%s (%s)", components[1], components[0]);
927
928             /*
929              * Charset is made up of fields 12 and 13.
930              */
931             charset = p;
932             p += 1 + sprintf(p, "%s-%s", components[12], components[13]);
933
934             /*
935              * Style is a mixture of quite a lot of the fields,
936              * with some strange formatting.
937              */
938             style = p;
939             p += sprintf(p, "%s", components[2][0] ? components[2] :
940                          "regular");
941             if (!g_ascii_strcasecmp(components[3], "i"))
942                 p += sprintf(p, " italic");
943             else if (!g_ascii_strcasecmp(components[3], "o"))
944                 p += sprintf(p, " oblique");
945             else if (!g_ascii_strcasecmp(components[3], "ri"))
946                 p += sprintf(p, " reverse italic");
947             else if (!g_ascii_strcasecmp(components[3], "ro"))
948                 p += sprintf(p, " reverse oblique");
949             else if (!g_ascii_strcasecmp(components[3], "ot"))
950                 p += sprintf(p, " other-slant");
951             if (components[4][0] && g_ascii_strcasecmp(components[4], "normal"))
952                 p += sprintf(p, " %s", components[4]);
953             if (!g_ascii_strcasecmp(components[10], "m"))
954                 p += sprintf(p, " [M]");
955             if (!g_ascii_strcasecmp(components[10], "c"))
956                 p += sprintf(p, " [C]");
957             if (components[5][0])
958                 p += sprintf(p, " %s", components[5]);
959
960             /*
961              * Style key is the same stuff as above, but with a
962              * couple of transformations done on it to make it
963              * sort more sensibly.
964              */
965             p++;
966             stylekey = p;
967             if (!g_ascii_strcasecmp(components[2], "medium") ||
968                 !g_ascii_strcasecmp(components[2], "regular") ||
969                 !g_ascii_strcasecmp(components[2], "normal") ||
970                 !g_ascii_strcasecmp(components[2], "book"))
971                 weightkey = 0;
972             else if (!g_ascii_strncasecmp(components[2], "demi", 4) ||
973                      !g_ascii_strncasecmp(components[2], "semi", 4))
974                 weightkey = 1;
975             else
976                 weightkey = 2;
977             if (!g_ascii_strcasecmp(components[3], "r"))
978                 slantkey = 0;
979             else if (!g_ascii_strncasecmp(components[3], "r", 1))
980                 slantkey = 2;
981             else
982                 slantkey = 1;
983             if (!g_ascii_strcasecmp(components[4], "normal"))
984                 setwidthkey = 0;
985             else
986                 setwidthkey = 1;
987
988             p += sprintf(p, "%04d%04d%s%04d%04d%s%04d%04d%s%04d%s%04d%s",
989                          weightkey,
990                          (int)strlen(components[2]), components[2],
991                          slantkey,
992                          (int)strlen(components[3]), components[3],
993                          setwidthkey,
994                          (int)strlen(components[4]), components[4],
995                          (int)strlen(components[10]), components[10],
996                          (int)strlen(components[5]), components[5]);
997
998             assert(p - tmp < thistmpsize);
999
1000             /*
1001              * Size is in pixels, for our application, so we
1002              * derive it directly from the pixel size field,
1003              * number 6.
1004              */
1005             fontsize = atoi(components[6]);
1006
1007             /*
1008              * Flags: we need to know whether this is a monospaced
1009              * font, which we do by examining the spacing field
1010              * again.
1011              */
1012             flags = FONTFLAG_SERVERSIDE;
1013             if (!strchr("CcMm", components[10][0]))
1014                 flags |= FONTFLAG_NONMONOSPACED;
1015
1016             /*
1017              * Not sure why, but sometimes the X server will
1018              * deliver dummy font types in which fontsize comes
1019              * out as zero. Filter those out.
1020              */
1021             if (fontsize)
1022                 callback(callback_ctx, fontnames[i], font, charset,
1023                          style, stylekey, fontsize, flags, &x11font_vtable);
1024         } else {
1025             /*
1026              * This isn't an XLFD, so it must be an alias.
1027              * Transmit it with mostly null data.
1028              * 
1029              * It would be nice to work out if it's monospaced
1030              * here, but at the moment I can't see that being
1031              * anything but computationally hideous. Ah well.
1032              */
1033             callback(callback_ctx, fontnames[i], fontnames[i], NULL,
1034                      NULL, NULL, 0, FONTFLAG_SERVERALIAS, &x11font_vtable);
1035         }
1036     }
1037     XFreeFontNames(fontnames);
1038 }
1039
1040 static char *x11font_canonify_fontname(GtkWidget *widget, const char *name,
1041                                        int *size, int *flags,
1042                                        int resolve_aliases)
1043 {
1044     /*
1045      * When given an X11 font name to try to make sense of for a
1046      * font selector, we must attempt to load it (to see if it
1047      * exists), and then canonify it by extracting its FONT
1048      * property, which should give its full XLFD even if what we
1049      * originally had was a wildcard.
1050      * 
1051      * However, we must carefully avoid canonifying font
1052      * _aliases_, unless specifically asked to, because the font
1053      * selector treats them as worthwhile in their own right.
1054      */
1055     XFontStruct *xfs;
1056     Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1057     Atom fontprop, fontprop2;
1058     unsigned long ret;
1059
1060     xfs = XLoadQueryFont(disp, name);
1061
1062     if (!xfs)
1063         return NULL;                   /* didn't make sense to us, sorry */
1064
1065     fontprop = XInternAtom(disp, "FONT", False);
1066
1067     if (XGetFontProperty(xfs, fontprop, &ret)) {
1068         char *newname = XGetAtomName(disp, (Atom)ret);
1069         if (newname) {
1070             unsigned long fsize = 12;
1071
1072             fontprop2 = XInternAtom(disp, "PIXEL_SIZE", False);
1073             if (XGetFontProperty(xfs, fontprop2, &fsize) && fsize > 0) {
1074                 *size = fsize;
1075                 XFreeFont(disp, xfs);
1076                 if (flags) {
1077                     if (name[0] == '-' || resolve_aliases)
1078                         *flags = FONTFLAG_SERVERSIDE;
1079                     else
1080                         *flags = FONTFLAG_SERVERALIAS;
1081                 }
1082                 return dupstr(name[0] == '-' || resolve_aliases ?
1083                               newname : name);
1084             }
1085         }
1086     }
1087
1088     XFreeFont(disp, xfs);
1089
1090     return NULL;                       /* something went wrong */
1091 }
1092
1093 static char *x11font_scale_fontname(GtkWidget *widget, const char *name,
1094                                     int size)
1095 {
1096     return NULL;                       /* shan't */
1097 }
1098
1099 #endif /* NOT_X_WINDOWS */
1100
1101 #if GTK_CHECK_VERSION(2,0,0)
1102
1103 /* ----------------------------------------------------------------------
1104  * Pango font implementation (for GTK 2 only).
1105  */
1106
1107 #if defined PANGO_PRE_1POINT4 && !defined PANGO_PRE_1POINT6
1108 #define PANGO_PRE_1POINT6              /* make life easier for pre-1.4 folk */
1109 #endif
1110
1111 static int pangofont_has_glyph(unifont *font, wchar_t glyph);
1112 static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
1113                                 int x, int y, const wchar_t *string, int len,
1114                                 int wide, int bold, int cellwidth);
1115 static unifont *pangofont_create(GtkWidget *widget, const char *name,
1116                                  int wide, int bold,
1117                                  int shadowoffset, int shadowalways);
1118 static unifont *pangofont_create_fallback(GtkWidget *widget, int height,
1119                                           int wide, int bold,
1120                                           int shadowoffset, int shadowalways);
1121 static void pangofont_destroy(unifont *font);
1122 static void pangofont_enum_fonts(GtkWidget *widget, fontsel_add_entry callback,
1123                                  void *callback_ctx);
1124 static char *pangofont_canonify_fontname(GtkWidget *widget, const char *name,
1125                                          int *size, int *flags,
1126                                          int resolve_aliases);
1127 static char *pangofont_scale_fontname(GtkWidget *widget, const char *name,
1128                                       int size);
1129
1130 struct pangofont {
1131     struct unifont u;
1132     /*
1133      * Pango objects.
1134      */
1135     PangoFontDescription *desc;
1136     PangoFontset *fset;
1137     /*
1138      * The containing widget.
1139      */
1140     GtkWidget *widget;
1141     /*
1142      * Data passed in to unifont_create().
1143      */
1144     int bold, shadowoffset, shadowalways;
1145     /*
1146      * Cache of character widths, indexed by Unicode code point. In
1147      * pixels; -1 means we haven't asked Pango about this character
1148      * before.
1149      */
1150     int *widthcache;
1151     unsigned nwidthcache;
1152 };
1153
1154 static const struct unifont_vtable pangofont_vtable = {
1155     pangofont_create,
1156     pangofont_create_fallback,
1157     pangofont_destroy,
1158     pangofont_has_glyph,
1159     pangofont_draw_text,
1160     pangofont_enum_fonts,
1161     pangofont_canonify_fontname,
1162     pangofont_scale_fontname,
1163     "client",
1164 };
1165
1166 /*
1167  * This function is used to rigorously validate a
1168  * PangoFontDescription. Later versions of Pango have a nasty
1169  * habit of accepting _any_ old string as input to
1170  * pango_font_description_from_string and returning a font
1171  * description which can actually be used to display text, even if
1172  * they have to do it by falling back to their most default font.
1173  * This is doubtless helpful in some situations, but not here,
1174  * because we need to know if a Pango font string actually _makes
1175  * sense_ in order to fall back to treating it as an X font name
1176  * if it doesn't. So we check that the font family is actually one
1177  * supported by Pango.
1178  */
1179 static int pangofont_check_desc_makes_sense(PangoContext *ctx,
1180                                             PangoFontDescription *desc)
1181 {
1182 #ifndef PANGO_PRE_1POINT6
1183     PangoFontMap *map;
1184 #endif
1185     PangoFontFamily **families;
1186     int i, nfamilies, matched;
1187
1188     /*
1189      * Ask Pango for a list of font families, and iterate through
1190      * them to see if one of them matches the family in the
1191      * PangoFontDescription.
1192      */
1193 #ifndef PANGO_PRE_1POINT6
1194     map = pango_context_get_font_map(ctx);
1195     if (!map)
1196         return FALSE;
1197     pango_font_map_list_families(map, &families, &nfamilies);
1198 #else
1199     pango_context_list_families(ctx, &families, &nfamilies);
1200 #endif
1201
1202     matched = FALSE;
1203     for (i = 0; i < nfamilies; i++) {
1204         if (!g_ascii_strcasecmp(pango_font_family_get_name(families[i]),
1205                                 pango_font_description_get_family(desc))) {
1206             matched = TRUE;
1207             break;
1208         }
1209     }
1210     g_free(families);
1211
1212     return matched;
1213 }
1214
1215 static unifont *pangofont_create_internal(GtkWidget *widget,
1216                                           PangoContext *ctx,
1217                                           PangoFontDescription *desc,
1218                                           int wide, int bold,
1219                                           int shadowoffset, int shadowalways)
1220 {
1221     struct pangofont *pfont;
1222 #ifndef PANGO_PRE_1POINT6
1223     PangoFontMap *map;
1224 #endif
1225     PangoFontset *fset;
1226     PangoFontMetrics *metrics;
1227
1228 #ifndef PANGO_PRE_1POINT6
1229     map = pango_context_get_font_map(ctx);
1230     if (!map) {
1231         pango_font_description_free(desc);
1232         return NULL;
1233     }
1234     fset = pango_font_map_load_fontset(map, ctx, desc,
1235                                        pango_context_get_language(ctx));
1236 #else
1237     fset = pango_context_load_fontset(ctx, desc,
1238                                       pango_context_get_language(ctx));
1239 #endif
1240     if (!fset) {
1241         pango_font_description_free(desc);
1242         return NULL;
1243     }
1244     metrics = pango_fontset_get_metrics(fset);
1245     if (!metrics ||
1246         pango_font_metrics_get_approximate_digit_width(metrics) == 0) {
1247         pango_font_description_free(desc);
1248         g_object_unref(fset);
1249         return NULL;
1250     }
1251
1252     pfont = snew(struct pangofont);
1253     pfont->u.vt = &pangofont_vtable;
1254     pfont->u.width =
1255         PANGO_PIXELS(pango_font_metrics_get_approximate_digit_width(metrics));
1256     pfont->u.ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics));
1257     pfont->u.descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
1258     pfont->u.height = pfont->u.ascent + pfont->u.descent;
1259     pfont->u.want_fallback = FALSE;
1260 #ifdef DRAW_TEXT_CAIRO
1261     pfont->u.preferred_drawtype = DRAWTYPE_CAIRO;
1262 #elif defined DRAW_TEXT_GDK
1263     pfont->u.preferred_drawtype = DRAWTYPE_GDK;
1264 #else
1265 #error No drawtype available at all
1266 #endif
1267     /* The Pango API is hardwired to UTF-8 */
1268     pfont->u.public_charset = CS_UTF8;
1269     pfont->desc = desc;
1270     pfont->fset = fset;
1271     pfont->widget = widget;
1272     pfont->bold = bold;
1273     pfont->shadowoffset = shadowoffset;
1274     pfont->shadowalways = shadowalways;
1275     pfont->widthcache = NULL;
1276     pfont->nwidthcache = 0;
1277
1278     pango_font_metrics_unref(metrics);
1279
1280     return (unifont *)pfont;
1281 }
1282
1283 static unifont *pangofont_create(GtkWidget *widget, const char *name,
1284                                  int wide, int bold,
1285                                  int shadowoffset, int shadowalways)
1286 {
1287     PangoContext *ctx;
1288     PangoFontDescription *desc;
1289
1290     desc = pango_font_description_from_string(name);
1291     if (!desc)
1292         return NULL;
1293     ctx = gtk_widget_get_pango_context(widget);
1294     if (!ctx) {
1295         pango_font_description_free(desc);
1296         return NULL;
1297     }
1298     if (!pangofont_check_desc_makes_sense(ctx, desc)) {
1299         pango_font_description_free(desc);
1300         return NULL;
1301     }
1302     return pangofont_create_internal(widget, ctx, desc, wide, bold,
1303                                      shadowoffset, shadowalways);
1304 }
1305
1306 static unifont *pangofont_create_fallback(GtkWidget *widget, int height,
1307                                           int wide, int bold,
1308                                           int shadowoffset, int shadowalways)
1309 {
1310     PangoContext *ctx;
1311     PangoFontDescription *desc;
1312
1313     desc = pango_font_description_from_string("Monospace");
1314     if (!desc)
1315         return NULL;
1316     ctx = gtk_widget_get_pango_context(widget);
1317     if (!ctx) {
1318         pango_font_description_free(desc);
1319         return NULL;
1320     }
1321     pango_font_description_set_absolute_size(desc, height * PANGO_SCALE);
1322     return pangofont_create_internal(widget, ctx, desc, wide, bold,
1323                                      shadowoffset, shadowalways);
1324 }
1325
1326 static void pangofont_destroy(unifont *font)
1327 {
1328     struct pangofont *pfont = (struct pangofont *)font;
1329     pango_font_description_free(pfont->desc);
1330     sfree(pfont->widthcache);
1331     g_object_unref(pfont->fset);
1332     sfree(font);
1333 }
1334
1335 static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont,
1336                                 wchar_t uchr, const char *utfchr, int utflen)
1337 {
1338     /*
1339      * Here we check whether a character has the same width as the
1340      * character cell it'll be drawn in. Because profiling showed that
1341      * asking Pango for text sizes was a huge bottleneck when we were
1342      * calling it every time we needed to know this, we instead call
1343      * it only on characters we don't already know about, and cache
1344      * the results.
1345      */
1346
1347     if ((unsigned)uchr >= pfont->nwidthcache) {
1348         unsigned newsize = ((int)uchr + 0x100) & ~0xFF;
1349         pfont->widthcache = sresize(pfont->widthcache, newsize, int);
1350         while (pfont->nwidthcache < newsize)
1351             pfont->widthcache[pfont->nwidthcache++] = -1;
1352     }
1353
1354     if (pfont->widthcache[uchr] < 0) {
1355         PangoRectangle rect;
1356         pango_layout_set_text(layout, utfchr, utflen);
1357         pango_layout_get_extents(layout, NULL, &rect);
1358         pfont->widthcache[uchr] = rect.width;
1359     }
1360
1361     return pfont->widthcache[uchr];
1362 }
1363
1364 static int pangofont_has_glyph(unifont *font, wchar_t glyph)
1365 {
1366     /* Pango implements font fallback, so assume it has everything */
1367     return TRUE;
1368 }
1369
1370 #ifdef DRAW_TEXT_GDK
1371 static void pango_gdk_draw_layout(unifont_drawctx *ctx,
1372                                   gint x, gint y, PangoLayout *layout)
1373 {
1374     gdk_draw_layout(ctx->u.gdk.target, ctx->u.gdk.gc, x, y, layout);
1375 }
1376 #endif
1377
1378 #ifdef DRAW_TEXT_CAIRO
1379 static void pango_cairo_draw_layout(unifont_drawctx *ctx,
1380                                     gint x, gint y, PangoLayout *layout)
1381 {
1382     cairo_move_to(ctx->u.cairo.cr, x, y);
1383     pango_cairo_show_layout(ctx->u.cairo.cr, layout);
1384 }
1385 #endif
1386
1387 static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
1388                                 int x, int y, const wchar_t *string, int len,
1389                                 int wide, int bold, int cellwidth)
1390 {
1391     struct pangofont *pfont = (struct pangofont *)font;
1392     PangoLayout *layout;
1393     PangoRectangle rect;
1394     char *utfstring, *utfptr;
1395     int utflen;
1396     int shadowbold = FALSE;
1397     void (*draw_layout)(unifont_drawctx *ctx,
1398                         gint x, gint y, PangoLayout *layout) = NULL;
1399
1400 #ifdef DRAW_TEXT_GDK
1401     if (ctx->type == DRAWTYPE_GDK) {
1402         draw_layout = pango_gdk_draw_layout;
1403     }
1404 #endif
1405 #ifdef DRAW_TEXT_CAIRO
1406     if (ctx->type == DRAWTYPE_CAIRO) {
1407         draw_layout = pango_cairo_draw_layout;
1408     }
1409 #endif
1410
1411     if (wide)
1412         cellwidth *= 2;
1413
1414     y -= pfont->u.ascent;
1415
1416     layout = pango_layout_new(gtk_widget_get_pango_context(pfont->widget));
1417     pango_layout_set_font_description(layout, pfont->desc);
1418     if (bold > pfont->bold) {
1419         if (pfont->shadowalways)
1420             shadowbold = TRUE;
1421         else {
1422             PangoFontDescription *desc2 =
1423                 pango_font_description_copy_static(pfont->desc);
1424             pango_font_description_set_weight(desc2, PANGO_WEIGHT_BOLD);
1425             pango_layout_set_font_description(layout, desc2);
1426         }
1427     }
1428
1429     /*
1430      * Pango always expects UTF-8, so convert the input wide character
1431      * string to UTF-8.
1432      */
1433     utfstring = snewn(len*6+1, char); /* UTF-8 has max 6 bytes/char */
1434     utflen = wc_to_mb(CS_UTF8, 0, string, len,
1435                       utfstring, len*6+1, ".", NULL, NULL);
1436
1437     utfptr = utfstring;
1438     while (utflen > 0) {
1439         int clen, n;
1440         int desired = cellwidth * PANGO_SCALE;
1441
1442         /*
1443          * We want to display every character from this string in
1444          * the centre of its own character cell. In the worst case,
1445          * this requires a separate text-drawing call for each
1446          * character; but in the common case where the font is
1447          * properly fixed-width, we can draw many characters in one
1448          * go which is much faster.
1449          *
1450          * This still isn't really ideal. If you look at what
1451          * happens in the X protocol as a result of all of this, you
1452          * find - naturally enough - that each call to
1453          * gdk_draw_layout() generates a separate set of X RENDER
1454          * operations involving creating a picture, setting a clip
1455          * rectangle, doing some drawing and undoing the whole lot.
1456          * In an ideal world, we should _always_ be able to turn the
1457          * contents of this loop into a single RenderCompositeGlyphs
1458          * operation which internally specifies inter-character
1459          * deltas to get the spacing right, which would give us full
1460          * speed _even_ in the worst case of a non-fixed-width font.
1461          * However, Pango's architecture and documentation are so
1462          * unhelpful that I have no idea how if at all to persuade
1463          * them to do that.
1464          */
1465
1466         /*
1467          * Start by extracting a single UTF-8 character from the
1468          * string.
1469          */
1470         clen = 1;
1471         while (clen < utflen &&
1472                (unsigned char)utfptr[clen] >= 0x80 &&
1473                (unsigned char)utfptr[clen] < 0xC0)
1474             clen++;
1475         n = 1;
1476
1477         if (is_rtl(string[0]) ||
1478             pangofont_char_width(layout, pfont, string[n-1],
1479                                  utfptr, clen) != desired) {
1480             /*
1481              * If this character is a right-to-left one, or has an
1482              * unusual width, then we must display it on its own.
1483              */
1484         } else {
1485             /*
1486              * Try to amalgamate a contiguous string of characters
1487              * with the expected sensible width, for the common case
1488              * in which we're using a monospaced font and everything
1489              * works as expected.
1490              */
1491             while (clen < utflen) {
1492                 int oldclen = clen;
1493                 clen++;                /* skip UTF-8 introducer byte */
1494                 while (clen < utflen &&
1495                        (unsigned char)utfptr[clen] >= 0x80 &&
1496                        (unsigned char)utfptr[clen] < 0xC0)
1497                     clen++;
1498                 n++;
1499                 if (pangofont_char_width(layout, pfont,
1500                                          string[n-1], utfptr + oldclen,
1501                                          clen - oldclen) != desired) {
1502                     clen = oldclen;
1503                     n--;
1504                     break;
1505                 }
1506             }
1507         }
1508
1509         pango_layout_set_text(layout, utfptr, clen);
1510         pango_layout_get_pixel_extents(layout, NULL, &rect);
1511         
1512         draw_layout(ctx,
1513                     x + (n*cellwidth - rect.width)/2,
1514                     y + (pfont->u.height - rect.height)/2, layout);
1515         if (shadowbold)
1516             draw_layout(ctx,
1517                         x + (n*cellwidth - rect.width)/2 + pfont->shadowoffset,
1518                         y + (pfont->u.height - rect.height)/2, layout);
1519
1520         utflen -= clen;
1521         utfptr += clen;
1522         string += n;
1523         x += n * cellwidth;
1524     }
1525
1526     sfree(utfstring);
1527
1528     g_object_unref(layout);
1529 }
1530
1531 /*
1532  * Dummy size value to be used when converting a
1533  * PangoFontDescription of a scalable font to a string for
1534  * internal use.
1535  */
1536 #define PANGO_DUMMY_SIZE 12
1537
1538 static void pangofont_enum_fonts(GtkWidget *widget, fontsel_add_entry callback,
1539                                  void *callback_ctx)
1540 {
1541     PangoContext *ctx;
1542 #ifndef PANGO_PRE_1POINT6
1543     PangoFontMap *map;
1544 #endif
1545     PangoFontFamily **families;
1546     int i, nfamilies;
1547
1548     ctx = gtk_widget_get_pango_context(widget);
1549     if (!ctx)
1550         return;
1551
1552     /*
1553      * Ask Pango for a list of font families, and iterate through
1554      * them.
1555      */
1556 #ifndef PANGO_PRE_1POINT6
1557     map = pango_context_get_font_map(ctx);
1558     if (!map)
1559         return;
1560     pango_font_map_list_families(map, &families, &nfamilies);
1561 #else
1562     pango_context_list_families(ctx, &families, &nfamilies);
1563 #endif
1564     for (i = 0; i < nfamilies; i++) {
1565         PangoFontFamily *family = families[i];
1566         const char *familyname;
1567         int flags;
1568         PangoFontFace **faces;
1569         int j, nfaces;
1570
1571         /*
1572          * Set up our flags for this font family, and get the name
1573          * string.
1574          */
1575         flags = FONTFLAG_CLIENTSIDE;
1576 #ifndef PANGO_PRE_1POINT4
1577         /*
1578          * In very early versions of Pango, we can't tell
1579          * monospaced fonts from non-monospaced.
1580          */
1581         if (!pango_font_family_is_monospace(family))
1582             flags |= FONTFLAG_NONMONOSPACED;
1583 #endif
1584         familyname = pango_font_family_get_name(family);
1585
1586         /*
1587          * Go through the available font faces in this family.
1588          */
1589         pango_font_family_list_faces(family, &faces, &nfaces);
1590         for (j = 0; j < nfaces; j++) {
1591             PangoFontFace *face = faces[j];
1592             PangoFontDescription *desc;
1593             const char *facename;
1594             int *sizes;
1595             int k, nsizes, dummysize;
1596
1597             /*
1598              * Get the face name string.
1599              */
1600             facename = pango_font_face_get_face_name(face);
1601
1602             /*
1603              * Set up a font description with what we've got so
1604              * far. We'll fill in the size field manually and then
1605              * call pango_font_description_to_string() to give the
1606              * full real name of the specific font.
1607              */
1608             desc = pango_font_face_describe(face);
1609
1610             /*
1611              * See if this font has a list of specific sizes.
1612              */
1613 #ifndef PANGO_PRE_1POINT4
1614             pango_font_face_list_sizes(face, &sizes, &nsizes);
1615 #else
1616             /*
1617              * In early versions of Pango, that call wasn't
1618              * supported; we just have to assume everything is
1619              * scalable.
1620              */
1621             sizes = NULL;
1622 #endif
1623             if (!sizes) {
1624                 /*
1625                  * Write a single entry with a dummy size.
1626                  */
1627                 dummysize = PANGO_DUMMY_SIZE * PANGO_SCALE;
1628                 sizes = &dummysize;
1629                 nsizes = 1;
1630             }
1631
1632             /*
1633              * If so, go through them one by one.
1634              */
1635             for (k = 0; k < nsizes; k++) {
1636                 char *fullname;
1637                 char stylekey[128];
1638
1639                 pango_font_description_set_size(desc, sizes[k]);
1640
1641                 fullname = pango_font_description_to_string(desc);
1642
1643                 /*
1644                  * Construct the sorting key for font styles.
1645                  */
1646                 {
1647                     char *p = stylekey;
1648                     int n;
1649
1650                     n = pango_font_description_get_weight(desc);
1651                     /* Weight: normal, then lighter, then bolder */
1652                     if (n <= PANGO_WEIGHT_NORMAL)
1653                         n = PANGO_WEIGHT_NORMAL - n;
1654                     p += sprintf(p, "%4d", n);
1655
1656                     n = pango_font_description_get_style(desc);
1657                     p += sprintf(p, " %2d", n);
1658
1659                     n = pango_font_description_get_stretch(desc);
1660                     /* Stretch: closer to normal sorts earlier */
1661                     n = 2 * abs(PANGO_STRETCH_NORMAL - n) +
1662                         (n < PANGO_STRETCH_NORMAL);
1663                     p += sprintf(p, " %2d", n);
1664
1665                     n = pango_font_description_get_variant(desc);
1666                     p += sprintf(p, " %2d", n);
1667                     
1668                 }
1669
1670                 /*
1671                  * Got everything. Hand off to the callback.
1672                  * (The charset string is NULL, because only
1673                  * server-side X fonts use it.)
1674                  */
1675                 callback(callback_ctx, fullname, familyname, NULL, facename,
1676                          stylekey,
1677                          (sizes == &dummysize ? 0 : PANGO_PIXELS(sizes[k])),
1678                          flags, &pangofont_vtable);
1679
1680                 g_free(fullname);
1681             }
1682             if (sizes != &dummysize)
1683                 g_free(sizes);
1684
1685             pango_font_description_free(desc);
1686         }
1687         g_free(faces);
1688     }
1689     g_free(families);
1690 }
1691
1692 static char *pangofont_canonify_fontname(GtkWidget *widget, const char *name,
1693                                          int *size, int *flags,
1694                                          int resolve_aliases)
1695 {
1696     /*
1697      * When given a Pango font name to try to make sense of for a
1698      * font selector, we must normalise it to PANGO_DUMMY_SIZE and
1699      * extract its original size (in pixels) into the `size' field.
1700      */
1701     PangoContext *ctx;
1702 #ifndef PANGO_PRE_1POINT6
1703     PangoFontMap *map;
1704 #endif
1705     PangoFontDescription *desc;
1706     PangoFontset *fset;
1707     PangoFontMetrics *metrics;
1708     char *newname, *retname;
1709
1710     desc = pango_font_description_from_string(name);
1711     if (!desc)
1712         return NULL;
1713     ctx = gtk_widget_get_pango_context(widget);
1714     if (!ctx) {
1715         pango_font_description_free(desc);
1716         return NULL;
1717     }
1718     if (!pangofont_check_desc_makes_sense(ctx, desc)) {
1719         pango_font_description_free(desc);
1720         return NULL;
1721     }
1722 #ifndef PANGO_PRE_1POINT6
1723     map = pango_context_get_font_map(ctx);
1724     if (!map) {
1725         pango_font_description_free(desc);
1726         return NULL;
1727     }
1728     fset = pango_font_map_load_fontset(map, ctx, desc,
1729                                        pango_context_get_language(ctx));
1730 #else
1731     fset = pango_context_load_fontset(ctx, desc,
1732                                       pango_context_get_language(ctx));
1733 #endif
1734     if (!fset) {
1735         pango_font_description_free(desc);
1736         return NULL;
1737     }
1738     metrics = pango_fontset_get_metrics(fset);
1739     if (!metrics ||
1740         pango_font_metrics_get_approximate_digit_width(metrics) == 0) {
1741         pango_font_description_free(desc);
1742         g_object_unref(fset);
1743         return NULL;
1744     }
1745
1746     *size = PANGO_PIXELS(pango_font_description_get_size(desc));
1747     *flags = FONTFLAG_CLIENTSIDE;
1748     pango_font_description_set_size(desc, PANGO_DUMMY_SIZE * PANGO_SCALE);
1749     newname = pango_font_description_to_string(desc);
1750     retname = dupstr(newname);
1751     g_free(newname);
1752
1753     pango_font_metrics_unref(metrics);
1754     pango_font_description_free(desc);
1755     g_object_unref(fset);
1756
1757     return retname;
1758 }
1759
1760 static char *pangofont_scale_fontname(GtkWidget *widget, const char *name,
1761                                       int size)
1762 {
1763     PangoFontDescription *desc;
1764     char *newname, *retname;
1765
1766     desc = pango_font_description_from_string(name);
1767     if (!desc)
1768         return NULL;
1769     pango_font_description_set_size(desc, size * PANGO_SCALE);
1770     newname = pango_font_description_to_string(desc);
1771     retname = dupstr(newname);
1772     g_free(newname);
1773     pango_font_description_free(desc);
1774
1775     return retname;
1776 }
1777
1778 #endif /* GTK_CHECK_VERSION(2,0,0) */
1779
1780 /* ----------------------------------------------------------------------
1781  * Outermost functions which do the vtable dispatch.
1782  */
1783
1784 /*
1785  * Complete list of font-type subclasses. Listed in preference
1786  * order for unifont_create(). (That is, in the extremely unlikely
1787  * event that the same font name is valid as both a Pango and an
1788  * X11 font, it will be interpreted as the former in the absence
1789  * of an explicit type-disambiguating prefix.)
1790  *
1791  * The 'multifont' subclass is omitted here, as discussed above.
1792  */
1793 static const struct unifont_vtable *unifont_types[] = {
1794 #if GTK_CHECK_VERSION(2,0,0)
1795     &pangofont_vtable,
1796 #endif
1797 #ifndef NOT_X_WINDOWS
1798     &x11font_vtable,
1799 #endif
1800 };
1801
1802 /*
1803  * Function which takes a font name and processes the optional
1804  * scheme prefix. Returns the tail of the font name suitable for
1805  * passing to individual font scheme functions, and also provides
1806  * a subrange of the unifont_types[] array above.
1807  * 
1808  * The return values `start' and `end' denote a half-open interval
1809  * in unifont_types[]; that is, the correct way to iterate over
1810  * them is
1811  * 
1812  *   for (i = start; i < end; i++) {...}
1813  */
1814 static const char *unifont_do_prefix(const char *name, int *start, int *end)
1815 {
1816     int colonpos = strcspn(name, ":");
1817     int i;
1818
1819     if (name[colonpos]) {
1820         /*
1821          * There's a colon prefix on the font name. Use it to work
1822          * out which subclass to use.
1823          */
1824         for (i = 0; i < lenof(unifont_types); i++) {
1825             if (strlen(unifont_types[i]->prefix) == colonpos &&
1826                 !strncmp(unifont_types[i]->prefix, name, colonpos)) {
1827                 *start = i;
1828                 *end = i+1;
1829                 return name + colonpos + 1;
1830             }
1831         }
1832         /*
1833          * None matched, so return an empty scheme list to prevent
1834          * any scheme from being called at all.
1835          */
1836         *start = *end = 0;
1837         return name + colonpos + 1;
1838     } else {
1839         /*
1840          * No colon prefix, so just use all the subclasses.
1841          */
1842         *start = 0;
1843         *end = lenof(unifont_types);
1844         return name;
1845     }
1846 }
1847
1848 unifont *unifont_create(GtkWidget *widget, const char *name, int wide,
1849                         int bold, int shadowoffset, int shadowalways)
1850 {
1851     int i, start, end;
1852
1853     name = unifont_do_prefix(name, &start, &end);
1854
1855     for (i = start; i < end; i++) {
1856         unifont *ret = unifont_types[i]->create(widget, name, wide, bold,
1857                                                 shadowoffset, shadowalways);
1858         if (ret)
1859             return ret;
1860     }
1861     return NULL;                       /* font not found in any scheme */
1862 }
1863
1864 void unifont_destroy(unifont *font)
1865 {
1866     font->vt->destroy(font);
1867 }
1868
1869 void unifont_draw_text(unifont_drawctx *ctx, unifont *font,
1870                        int x, int y, const wchar_t *string, int len,
1871                        int wide, int bold, int cellwidth)
1872 {
1873     font->vt->draw_text(ctx, font, x, y, string, len, wide, bold, cellwidth);
1874 }
1875
1876 /* ----------------------------------------------------------------------
1877  * Multiple-font wrapper. This is a type of unifont which encapsulates
1878  * up to two other unifonts, permitting missing glyphs in the main
1879  * font to be filled in by a fallback font.
1880  *
1881  * This is a type of unifont just like the previous two, but it has a
1882  * separate constructor which is manually called by the client, so it
1883  * doesn't appear in the list of available font types enumerated by
1884  * unifont_create. This means it's not used by unifontsel either, so
1885  * it doesn't need to support any methods except draw_text and
1886  * destroy.
1887  */
1888
1889 static void multifont_draw_text(unifont_drawctx *ctx, unifont *font,
1890                                 int x, int y, const wchar_t *string, int len,
1891                                 int wide, int bold, int cellwidth);
1892 static void multifont_destroy(unifont *font);
1893
1894 struct multifont {
1895     struct unifont u;
1896     unifont *main;
1897     unifont *fallback;
1898 };
1899
1900 static const struct unifont_vtable multifont_vtable = {
1901     NULL,                             /* creation is done specially */
1902     NULL,
1903     multifont_destroy,
1904     NULL,
1905     multifont_draw_text,
1906     NULL,
1907     NULL,
1908     NULL,
1909     "client",
1910 };
1911
1912 unifont *multifont_create(GtkWidget *widget, const char *name,
1913                           int wide, int bold,
1914                           int shadowoffset, int shadowalways)
1915 {
1916     int i;
1917     unifont *font, *fallback;
1918     struct multifont *mfont;
1919
1920     font = unifont_create(widget, name, wide, bold,
1921                           shadowoffset, shadowalways);
1922     if (!font)
1923         return NULL;
1924
1925     fallback = NULL;
1926     if (font->want_fallback) {
1927         for (i = 0; i < lenof(unifont_types); i++) {
1928             if (unifont_types[i]->create_fallback) {
1929                 fallback = unifont_types[i]->create_fallback
1930                     (widget, font->height, wide, bold,
1931                      shadowoffset, shadowalways);
1932                 if (fallback)
1933                     break;
1934             }
1935         }
1936     }
1937
1938     /*
1939      * Construct our multifont. Public members are all copied from the
1940      * primary font we're wrapping.
1941      */
1942     mfont = snew(struct multifont);
1943     mfont->u.vt = &multifont_vtable;
1944     mfont->u.width = font->width;
1945     mfont->u.ascent = font->ascent;
1946     mfont->u.descent = font->descent;
1947     mfont->u.height = font->height;
1948     mfont->u.public_charset = font->public_charset;
1949     mfont->u.want_fallback = FALSE; /* shouldn't be needed, but just in case */
1950     mfont->u.preferred_drawtype = font->preferred_drawtype;
1951     mfont->main = font;
1952     mfont->fallback = fallback;
1953
1954     return (unifont *)mfont;
1955 }
1956
1957 static void multifont_destroy(unifont *font)
1958 {
1959     struct multifont *mfont = (struct multifont *)font;
1960     unifont_destroy(mfont->main);
1961     if (mfont->fallback)
1962         unifont_destroy(mfont->fallback);
1963     sfree(font);
1964 }
1965
1966 static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x,
1967                                 int y, const wchar_t *string, int len,
1968                                 int wide, int bold, int cellwidth)
1969 {
1970     struct multifont *mfont = (struct multifont *)font;
1971     unifont *f;
1972     int ok, i;
1973
1974     while (len > 0) {
1975         /*
1976          * Find a maximal sequence of characters which are, or are
1977          * not, supported by our main font.
1978          */
1979         ok = mfont->main->vt->has_glyph(mfont->main, string[0]);
1980         for (i = 1;
1981              i < len &&
1982              !mfont->main->vt->has_glyph(mfont->main, string[i]) == !ok;
1983              i++);
1984
1985         /*
1986          * Now display it.
1987          */
1988         f = ok ? mfont->main : mfont->fallback;
1989         if (f)
1990             unifont_draw_text(ctx, f, x, y, string, i, wide, bold, cellwidth);
1991         string += i;
1992         len -= i;
1993         x += i * cellwidth;
1994     }
1995 }
1996
1997 #if GTK_CHECK_VERSION(2,0,0)
1998
1999 /* ----------------------------------------------------------------------
2000  * Implementation of a unified font selector. Used on GTK 2 only;
2001  * for GTK 1 we still use the standard font selector.
2002  */
2003
2004 typedef struct fontinfo fontinfo;
2005
2006 typedef struct unifontsel_internal {
2007     /* This must be the structure's first element, for cross-casting */
2008     unifontsel u;
2009     GtkListStore *family_model, *style_model, *size_model;
2010     GtkWidget *family_list, *style_list, *size_entry, *size_list;
2011     GtkWidget *filter_buttons[4];
2012     int n_filter_buttons;
2013     GtkWidget *preview_area;
2014 #ifndef NO_BACKING_PIXMAPS
2015     GdkPixmap *preview_pixmap;
2016 #endif
2017     int preview_width, preview_height;
2018     GdkColor preview_fg, preview_bg;
2019     int filter_flags;
2020     tree234 *fonts_by_realname, *fonts_by_selorder;
2021     fontinfo *selected;
2022     int selsize, intendedsize;
2023     int inhibit_response;  /* inhibit callbacks when we change GUI controls */
2024 } unifontsel_internal;
2025
2026 /*
2027  * The structure held in the tree234s. All the string members are
2028  * part of the same allocated area, so don't need freeing
2029  * separately.
2030  */
2031 struct fontinfo {
2032     char *realname;
2033     char *family, *charset, *style, *stylekey;
2034     int size, flags;
2035     /*
2036      * Fallback sorting key, to permit multiple identical entries
2037      * to exist in the selorder tree.
2038      */
2039     int index;
2040     /*
2041      * Indices mapping fontinfo structures to indices in the list
2042      * boxes. sizeindex is irrelevant if the font is scalable
2043      * (size==0).
2044      */
2045     int familyindex, styleindex, sizeindex;
2046     /*
2047      * The class of font.
2048      */
2049     const struct unifont_vtable *fontclass;
2050 };
2051
2052 struct fontinfo_realname_find {
2053     const char *realname;
2054     int flags;
2055 };
2056
2057 static int strnullcasecmp(const char *a, const char *b)
2058 {
2059     int i;
2060
2061     /*
2062      * If exactly one of the inputs is NULL, it compares before
2063      * the other one.
2064      */
2065     if ((i = (!b) - (!a)) != 0)
2066         return i;
2067
2068     /*
2069      * NULL compares equal.
2070      */
2071     if (!a)
2072         return 0;
2073
2074     /*
2075      * Otherwise, ordinary strcasecmp.
2076      */
2077     return g_ascii_strcasecmp(a, b);
2078 }
2079
2080 static int fontinfo_realname_compare(void *av, void *bv)
2081 {
2082     fontinfo *a = (fontinfo *)av;
2083     fontinfo *b = (fontinfo *)bv;
2084     int i;
2085
2086     if ((i = strnullcasecmp(a->realname, b->realname)) != 0)
2087         return i;
2088     if ((a->flags & FONTFLAG_SORT_MASK) != (b->flags & FONTFLAG_SORT_MASK))
2089         return ((a->flags & FONTFLAG_SORT_MASK) <
2090                 (b->flags & FONTFLAG_SORT_MASK) ? -1 : +1);
2091     return 0;
2092 }
2093
2094 static int fontinfo_realname_find(void *av, void *bv)
2095 {
2096     struct fontinfo_realname_find *a = (struct fontinfo_realname_find *)av;
2097     fontinfo *b = (fontinfo *)bv;
2098     int i;
2099
2100     if ((i = strnullcasecmp(a->realname, b->realname)) != 0)
2101         return i;
2102     if ((a->flags & FONTFLAG_SORT_MASK) != (b->flags & FONTFLAG_SORT_MASK))
2103         return ((a->flags & FONTFLAG_SORT_MASK) <
2104                 (b->flags & FONTFLAG_SORT_MASK) ? -1 : +1);
2105     return 0;
2106 }
2107
2108 static int fontinfo_selorder_compare(void *av, void *bv)
2109 {
2110     fontinfo *a = (fontinfo *)av;
2111     fontinfo *b = (fontinfo *)bv;
2112     int i;
2113     if ((i = strnullcasecmp(a->family, b->family)) != 0)
2114         return i;
2115     /*
2116      * Font class comes immediately after family, so that fonts
2117      * from different classes with the same family
2118      */
2119     if ((a->flags & FONTFLAG_SORT_MASK) != (b->flags & FONTFLAG_SORT_MASK))
2120         return ((a->flags & FONTFLAG_SORT_MASK) <
2121                 (b->flags & FONTFLAG_SORT_MASK) ? -1 : +1);
2122     if ((i = strnullcasecmp(a->charset, b->charset)) != 0)
2123         return i;
2124     if ((i = strnullcasecmp(a->stylekey, b->stylekey)) != 0)
2125         return i;
2126     if ((i = strnullcasecmp(a->style, b->style)) != 0)
2127         return i;
2128     if (a->size != b->size)
2129         return (a->size < b->size ? -1 : +1);
2130     if (a->index != b->index)
2131         return (a->index < b->index ? -1 : +1);
2132     return 0;
2133 }
2134
2135 static void unifontsel_draw_preview_text(unifontsel_internal *fs);
2136
2137 static void unifontsel_deselect(unifontsel_internal *fs)
2138 {
2139     fs->selected = NULL;
2140     gtk_list_store_clear(fs->style_model);
2141     gtk_list_store_clear(fs->size_model);
2142     gtk_widget_set_sensitive(fs->u.ok_button, FALSE);
2143     gtk_widget_set_sensitive(fs->size_entry, FALSE);
2144     unifontsel_draw_preview_text(fs);
2145 }
2146
2147 static void unifontsel_setup_familylist(unifontsel_internal *fs)
2148 {
2149     GtkTreeIter iter;
2150     int i, listindex, minpos = -1, maxpos = -1;
2151     char *currfamily = NULL;
2152     int currflags = -1;
2153     fontinfo *info;
2154
2155     fs->inhibit_response = TRUE;
2156
2157     gtk_list_store_clear(fs->family_model);
2158     listindex = 0;
2159
2160     /*
2161      * Search through the font tree for anything matching our
2162      * current filter criteria. When we find one, add its font
2163      * name to the list box.
2164      */
2165     for (i = 0 ;; i++) {
2166         info = (fontinfo *)index234(fs->fonts_by_selorder, i);
2167         /*
2168          * info may be NULL if we've just run off the end of the
2169          * tree. We must still do a processing pass in that
2170          * situation, in case we had an unfinished font record in
2171          * progress.
2172          */
2173         if (info && (info->flags &~ fs->filter_flags)) {
2174             info->familyindex = -1;
2175             continue;                  /* we're filtering out this font */
2176         }
2177         if (!info || strnullcasecmp(currfamily, info->family) ||
2178             currflags != (info->flags & FONTFLAG_SORT_MASK)) {
2179             /*
2180              * We've either finished a family, or started a new
2181              * one, or both.
2182              */
2183             if (currfamily) {
2184                 gtk_list_store_append(fs->family_model, &iter);
2185                 gtk_list_store_set(fs->family_model, &iter,
2186                                    0, currfamily, 1, minpos, 2, maxpos+1, -1);
2187                 listindex++;
2188             }
2189             if (info) {
2190                 minpos = i;
2191                 currfamily = info->family;
2192                 currflags = info->flags & FONTFLAG_SORT_MASK;
2193             }
2194         }
2195         if (!info)
2196             break;                     /* now we're done */
2197         info->familyindex = listindex;
2198         maxpos = i;
2199     }
2200
2201     /*
2202      * If we've just filtered out the previously selected font,
2203      * deselect it thoroughly.
2204      */
2205     if (fs->selected && fs->selected->familyindex < 0)
2206         unifontsel_deselect(fs);
2207
2208     fs->inhibit_response = FALSE;
2209 }
2210
2211 static void unifontsel_setup_stylelist(unifontsel_internal *fs,
2212                                        int start, int end)
2213 {
2214     GtkTreeIter iter;
2215     int i, listindex, minpos = -1, maxpos = -1, started = FALSE;
2216     char *currcs = NULL, *currstyle = NULL;
2217     fontinfo *info;
2218
2219     gtk_list_store_clear(fs->style_model);
2220     listindex = 0;
2221     started = FALSE;
2222
2223     /*
2224      * Search through the font tree for anything matching our
2225      * current filter criteria. When we find one, add its charset
2226      * and/or style name to the list box.
2227      */
2228     for (i = start; i <= end; i++) {
2229         if (i == end)
2230             info = NULL;
2231         else
2232             info = (fontinfo *)index234(fs->fonts_by_selorder, i);
2233         /*
2234          * info may be NULL if we've just run off the end of the
2235          * relevant data. We must still do a processing pass in
2236          * that situation, in case we had an unfinished font
2237          * record in progress.
2238          */
2239         if (info && (info->flags &~ fs->filter_flags)) {
2240             info->styleindex = -1;
2241             continue;                  /* we're filtering out this font */
2242         }
2243         if (!info || !started || strnullcasecmp(currcs, info->charset) ||
2244              strnullcasecmp(currstyle, info->style)) {
2245             /*
2246              * We've either finished a style/charset, or started a
2247              * new one, or both.
2248              */
2249             started = TRUE;
2250             if (currstyle) {
2251                 gtk_list_store_append(fs->style_model, &iter);
2252                 gtk_list_store_set(fs->style_model, &iter,
2253                                    0, currstyle, 1, minpos, 2, maxpos+1,
2254                                    3, TRUE, -1);
2255                 listindex++;
2256             }
2257             if (info) {
2258                 minpos = i;
2259                 if (info->charset && strnullcasecmp(currcs, info->charset)) {
2260                     gtk_list_store_append(fs->style_model, &iter);
2261                     gtk_list_store_set(fs->style_model, &iter,
2262                                        0, info->charset, 1, -1, 2, -1,
2263                                        3, FALSE, -1);
2264                     listindex++;
2265                 }
2266                 currcs = info->charset;
2267                 currstyle = info->style;
2268             }
2269         }
2270         if (!info)
2271             break;                     /* now we're done */
2272         info->styleindex = listindex;
2273         maxpos = i;
2274     }
2275 }
2276
2277 static const int unifontsel_default_sizes[] = { 10, 12, 14, 16, 20, 24, 32 };
2278
2279 static void unifontsel_setup_sizelist(unifontsel_internal *fs,
2280                                       int start, int end)
2281 {
2282     GtkTreeIter iter;
2283     int i, listindex;
2284     char sizetext[40];
2285     fontinfo *info;
2286
2287     gtk_list_store_clear(fs->size_model);
2288     listindex = 0;
2289
2290     /*
2291      * Search through the font tree for anything matching our
2292      * current filter criteria. When we find one, add its font
2293      * name to the list box.
2294      */
2295     for (i = start; i < end; i++) {
2296         info = (fontinfo *)index234(fs->fonts_by_selorder, i);
2297         if (info->flags &~ fs->filter_flags) {
2298             info->sizeindex = -1;
2299             continue;                  /* we're filtering out this font */
2300         }
2301         if (info->size) {
2302             sprintf(sizetext, "%d", info->size);
2303             info->sizeindex = listindex;
2304             gtk_list_store_append(fs->size_model, &iter);
2305             gtk_list_store_set(fs->size_model, &iter,
2306                                0, sizetext, 1, i, 2, info->size, -1);
2307             listindex++;
2308         } else {
2309             int j;
2310
2311             assert(i == start);
2312             assert(i+1 == end);
2313
2314             for (j = 0; j < lenof(unifontsel_default_sizes); j++) {
2315                 sprintf(sizetext, "%d", unifontsel_default_sizes[j]);
2316                 gtk_list_store_append(fs->size_model, &iter);
2317                 gtk_list_store_set(fs->size_model, &iter, 0, sizetext, 1, i,
2318                                    2, unifontsel_default_sizes[j], -1);
2319                 listindex++;
2320             }
2321         }
2322     }
2323 }
2324
2325 static void unifontsel_set_filter_buttons(unifontsel_internal *fs)
2326 {
2327     int i;
2328
2329     for (i = 0; i < fs->n_filter_buttons; i++) {
2330         int flagbit = GPOINTER_TO_INT(g_object_get_data
2331                                       (G_OBJECT(fs->filter_buttons[i]),
2332                                        "user-data"));
2333         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fs->filter_buttons[i]),
2334                                      !!(fs->filter_flags & flagbit));
2335     }
2336 }
2337
2338 static void unifontsel_draw_preview_text_inner(unifont_drawctx *dctx,
2339                                                unifontsel_internal *fs)
2340 {
2341     unifont *font;
2342     char *sizename = NULL;
2343     fontinfo *info = fs->selected;
2344
2345     if (info) {
2346         sizename = info->fontclass->scale_fontname
2347             (GTK_WIDGET(fs->u.window), info->realname, fs->selsize);
2348         font = info->fontclass->create(GTK_WIDGET(fs->u.window),
2349                                        sizename ? sizename : info->realname,
2350                                        FALSE, FALSE, 0, 0);
2351     } else
2352         font = NULL;
2353
2354 #ifdef DRAW_TEXT_GDK
2355     if (dctx->type == DRAWTYPE_GDK) {
2356         gdk_gc_set_foreground(dctx->u.gdk.gc, &fs->preview_bg);
2357         gdk_draw_rectangle(dctx->u.gdk.target, dctx->u.gdk.gc, 1, 0, 0,
2358                            fs->preview_width, fs->preview_height);
2359         gdk_gc_set_foreground(dctx->u.gdk.gc, &fs->preview_fg);
2360     }
2361 #endif
2362 #ifdef DRAW_TEXT_CAIRO
2363     if (dctx->type == DRAWTYPE_CAIRO) {
2364         cairo_set_source_rgb(dctx->u.cairo.cr,
2365                              fs->preview_bg.red / 65535.0,
2366                              fs->preview_bg.green / 65535.0,
2367                              fs->preview_bg.blue / 65535.0);
2368         cairo_paint(dctx->u.cairo.cr);
2369         cairo_set_source_rgb(dctx->u.cairo.cr,
2370                              fs->preview_fg.red / 65535.0,
2371                              fs->preview_fg.green / 65535.0,
2372                              fs->preview_fg.blue / 65535.0);
2373     }
2374 #endif
2375
2376     if (font) {
2377         /*
2378          * The pangram used here is rather carefully
2379          * constructed: it contains a sequence of very narrow
2380          * letters (`jil') and a pair of adjacent very wide
2381          * letters (`wm').
2382          *
2383          * If the user selects a proportional font, it will be
2384          * coerced into fixed-width character cells when used
2385          * in the actual terminal window. We therefore display
2386          * it the same way in the preview pane, so as to show
2387          * it the way it will actually be displayed - and we
2388          * deliberately pick a pangram which will show the
2389          * resulting miskerning at its worst.
2390          *
2391          * We aren't trying to sell people these fonts; we're
2392          * trying to let them make an informed choice. Better
2393          * that they find out the problems with using
2394          * proportional fonts in terminal windows here than
2395          * that they go to the effort of selecting their font
2396          * and _then_ realise it was a mistake.
2397          */
2398         info->fontclass->draw_text(dctx, font,
2399                                    0, font->ascent,
2400                                    L"bankrupt jilted showmen quiz convex fogey",
2401                                    41, FALSE, FALSE, font->width);
2402         info->fontclass->draw_text(dctx, font,
2403                                    0, font->ascent + font->height,
2404                                    L"BANKRUPT JILTED SHOWMEN QUIZ CONVEX FOGEY",
2405                                    41, FALSE, FALSE, font->width);
2406         /*
2407          * The ordering of punctuation here is also selected
2408          * with some specific aims in mind. I put ` and '
2409          * together because some software (and people) still
2410          * use them as matched quotes no matter what Unicode
2411          * might say on the matter, so people can quickly
2412          * check whether they look silly in a candidate font.
2413          * The sequence #_@ is there to let people judge the
2414          * suitability of the underscore as an effectively
2415          * alphabetic character (since that's how it's often
2416          * used in practice, at least by programmers).
2417          */
2418         info->fontclass->draw_text(dctx, font,
2419                                    0, font->ascent + font->height * 2,
2420                                    L"0123456789!?,.:;<>()[]{}\\/`'\"+*-=~#_@|%&^$",
2421                                    42, FALSE, FALSE, font->width);
2422
2423         info->fontclass->destroy(font);
2424     }
2425
2426     sfree(sizename);
2427 }
2428
2429 static void unifontsel_draw_preview_text(unifontsel_internal *fs)
2430 {
2431     unifont_drawctx dctx;
2432     GdkWindow *target;
2433
2434 #ifndef NO_BACKING_PIXMAPS
2435     target = fs->preview_pixmap;
2436 #else
2437     target = gtk_widget_get_window(fs->preview_area);
2438 #endif
2439     if (!target) /* we may be called when we haven't created everything yet */
2440         return;
2441
2442     dctx.type = DRAWTYPE_DEFAULT;
2443 #ifdef DRAW_TEXT_GDK
2444     if (dctx.type == DRAWTYPE_GDK) {
2445         dctx.u.gdk.target = target;
2446         dctx.u.gdk.gc = gdk_gc_new(target);
2447     }
2448 #endif
2449 #ifdef DRAW_TEXT_CAIRO
2450     if (dctx.type == DRAWTYPE_CAIRO) {
2451         dctx.u.cairo.widget = GTK_WIDGET(fs->preview_area);
2452         dctx.u.cairo.cr = gdk_cairo_create(target);
2453     }
2454 #endif
2455
2456     unifontsel_draw_preview_text_inner(&dctx, fs);
2457
2458 #ifdef DRAW_TEXT_GDK
2459     if (dctx.type == DRAWTYPE_GDK) {
2460         gdk_gc_unref(dctx.u.gdk.gc);
2461     }
2462 #endif
2463 #ifdef DRAW_TEXT_CAIRO
2464     if (dctx.type == DRAWTYPE_CAIRO) {
2465         cairo_destroy(dctx.u.cairo.cr);
2466     }
2467 #endif
2468
2469     gdk_window_invalidate_rect(gtk_widget_get_window(fs->preview_area),
2470                                NULL, FALSE);
2471 }
2472
2473 static void unifontsel_select_font(unifontsel_internal *fs,
2474                                    fontinfo *info, int size, int leftlist,
2475                                    int size_is_explicit)
2476 {
2477     int index;
2478     int minval, maxval;
2479     gboolean success;
2480     GtkTreePath *treepath;
2481     GtkTreeIter iter;
2482
2483     fs->inhibit_response = TRUE;
2484
2485     fs->selected = info;
2486     fs->selsize = size;
2487     if (size_is_explicit)
2488         fs->intendedsize = size;
2489
2490     gtk_widget_set_sensitive(fs->u.ok_button, TRUE);
2491
2492     /*
2493      * Find the index of this fontinfo in the selorder list. 
2494      */
2495     index = -1;
2496     findpos234(fs->fonts_by_selorder, info, NULL, &index);
2497     assert(index >= 0);
2498
2499     /*
2500      * Adjust the font selector flags and redo the font family
2501      * list box, if necessary.
2502      */
2503     if (leftlist <= 0 &&
2504         (fs->filter_flags | info->flags) != fs->filter_flags) {
2505         fs->filter_flags |= info->flags;
2506         unifontsel_set_filter_buttons(fs);
2507         unifontsel_setup_familylist(fs);
2508     }
2509
2510     /*
2511      * Find the appropriate family name and select it in the list.
2512      */
2513     assert(info->familyindex >= 0);
2514     treepath = gtk_tree_path_new_from_indices(info->familyindex, -1);
2515     gtk_tree_selection_select_path
2516         (gtk_tree_view_get_selection(GTK_TREE_VIEW(fs->family_list)),
2517          treepath);
2518     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->family_list),
2519                                  treepath, NULL, FALSE, 0.0, 0.0);
2520     success = gtk_tree_model_get_iter(GTK_TREE_MODEL(fs->family_model),
2521                                       &iter, treepath);
2522     assert(success);
2523     gtk_tree_path_free(treepath);
2524
2525     /*
2526      * Now set up the font style list.
2527      */
2528     gtk_tree_model_get(GTK_TREE_MODEL(fs->family_model), &iter,
2529                        1, &minval, 2, &maxval, -1);
2530     if (leftlist <= 1)
2531         unifontsel_setup_stylelist(fs, minval, maxval);
2532
2533     /*
2534      * Find the appropriate style name and select it in the list.
2535      */
2536     if (info->style) {
2537         assert(info->styleindex >= 0);
2538         treepath = gtk_tree_path_new_from_indices(info->styleindex, -1);
2539         gtk_tree_selection_select_path
2540             (gtk_tree_view_get_selection(GTK_TREE_VIEW(fs->style_list)),
2541              treepath);
2542         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->style_list),
2543                                      treepath, NULL, FALSE, 0.0, 0.0);
2544         gtk_tree_model_get_iter(GTK_TREE_MODEL(fs->style_model),
2545                                 &iter, treepath);
2546         gtk_tree_path_free(treepath);
2547
2548         /*
2549          * And set up the size list.
2550          */
2551         gtk_tree_model_get(GTK_TREE_MODEL(fs->style_model), &iter,
2552                            1, &minval, 2, &maxval, -1);
2553         if (leftlist <= 2)
2554             unifontsel_setup_sizelist(fs, minval, maxval);
2555
2556         /*
2557          * Find the appropriate size, and select it in the list.
2558          */
2559         if (info->size) {
2560             assert(info->sizeindex >= 0);
2561             treepath = gtk_tree_path_new_from_indices(info->sizeindex, -1);
2562             gtk_tree_selection_select_path
2563                 (gtk_tree_view_get_selection(GTK_TREE_VIEW(fs->size_list)),
2564                  treepath);
2565             gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->size_list),
2566                                          treepath, NULL, FALSE, 0.0, 0.0);
2567             gtk_tree_path_free(treepath);
2568             size = info->size;
2569         } else {
2570             int j;
2571             for (j = 0; j < lenof(unifontsel_default_sizes); j++)
2572                 if (unifontsel_default_sizes[j] == size) {
2573                     treepath = gtk_tree_path_new_from_indices(j, -1);
2574                     gtk_tree_view_set_cursor(GTK_TREE_VIEW(fs->size_list),
2575                                              treepath, NULL, FALSE);
2576                     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->size_list),
2577                                                  treepath, NULL, FALSE, 0.0,
2578                                                  0.0);
2579                     gtk_tree_path_free(treepath);
2580                 }
2581         }
2582
2583         /*
2584          * And set up the font size text entry box.
2585          */
2586         {
2587             char sizetext[40];
2588             sprintf(sizetext, "%d", size);
2589             gtk_entry_set_text(GTK_ENTRY(fs->size_entry), sizetext);
2590         }
2591     } else {
2592         if (leftlist <= 2)
2593             unifontsel_setup_sizelist(fs, 0, 0);
2594         gtk_entry_set_text(GTK_ENTRY(fs->size_entry), "");
2595     }
2596
2597     /*
2598      * Grey out the font size edit box if we're not using a
2599      * scalable font.
2600      */
2601     gtk_editable_set_editable(GTK_EDITABLE(fs->size_entry),
2602                               fs->selected->size == 0);
2603     gtk_widget_set_sensitive(fs->size_entry, fs->selected->size == 0);
2604
2605     unifontsel_draw_preview_text(fs);
2606
2607     fs->inhibit_response = FALSE;
2608 }
2609
2610 static void unifontsel_button_toggled(GtkToggleButton *tb, gpointer data)
2611 {
2612     unifontsel_internal *fs = (unifontsel_internal *)data;
2613     int newstate = gtk_toggle_button_get_active(tb);
2614     int newflags;
2615     int flagbit = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tb),
2616                                                     "user-data"));
2617
2618     if (newstate)
2619         newflags = fs->filter_flags | flagbit;
2620     else
2621         newflags = fs->filter_flags & ~flagbit;
2622
2623     if (fs->filter_flags != newflags) {
2624         fs->filter_flags = newflags;
2625         unifontsel_setup_familylist(fs);
2626     }
2627 }
2628
2629 static void unifontsel_add_entry(void *ctx, const char *realfontname,
2630                                  const char *family, const char *charset,
2631                                  const char *style, const char *stylekey,
2632                                  int size, int flags,
2633                                  const struct unifont_vtable *fontclass)
2634 {
2635     unifontsel_internal *fs = (unifontsel_internal *)ctx;
2636     fontinfo *info;
2637     int totalsize;
2638     char *p;
2639
2640     totalsize = sizeof(fontinfo) + strlen(realfontname) +
2641         (family ? strlen(family) : 0) + (charset ? strlen(charset) : 0) +
2642         (style ? strlen(style) : 0) + (stylekey ? strlen(stylekey) : 0) + 10;
2643     info = (fontinfo *)smalloc(totalsize);
2644     info->fontclass = fontclass;
2645     p = (char *)info + sizeof(fontinfo);
2646     info->realname = p;
2647     strcpy(p, realfontname);
2648     p += 1+strlen(p);
2649     if (family) {
2650         info->family = p;
2651         strcpy(p, family);
2652         p += 1+strlen(p);
2653     } else
2654         info->family = NULL;
2655     if (charset) {
2656         info->charset = p;
2657         strcpy(p, charset);
2658         p += 1+strlen(p);
2659     } else
2660         info->charset = NULL;
2661     if (style) {
2662         info->style = p;
2663         strcpy(p, style);
2664         p += 1+strlen(p);
2665     } else
2666         info->style = NULL;
2667     if (stylekey) {
2668         info->stylekey = p;
2669         strcpy(p, stylekey);
2670         p += 1+strlen(p);
2671     } else
2672         info->stylekey = NULL;
2673     assert(p - (char *)info <= totalsize);
2674     info->size = size;
2675     info->flags = flags;
2676     info->index = count234(fs->fonts_by_selorder);
2677
2678     /*
2679      * It's just conceivable that a misbehaving font enumerator
2680      * might tell us about the same font real name more than once,
2681      * in which case we should silently drop the new one.
2682      */
2683     if (add234(fs->fonts_by_realname, info) != info) {
2684         sfree(info);
2685         return;
2686     }
2687     /*
2688      * However, we should never get a duplicate key in the
2689      * selorder tree, because the index field carefully
2690      * disambiguates otherwise identical records.
2691      */
2692     add234(fs->fonts_by_selorder, info);
2693 }
2694
2695 static fontinfo *update_for_intended_size(unifontsel_internal *fs,
2696                                           fontinfo *info)
2697 {
2698     fontinfo info2, *below, *above;
2699     int pos;
2700
2701     /*
2702      * Copy the info structure. This doesn't copy its dynamic
2703      * string fields, but that's unimportant because all we're
2704      * going to do is to adjust the size field and use it in one
2705      * tree search.
2706      */
2707     info2 = *info;
2708     info2.size = fs->intendedsize;
2709
2710     /*
2711      * Search in the tree to find the fontinfo structure which
2712      * best approximates the size the user last requested.
2713      */
2714     below = findrelpos234(fs->fonts_by_selorder, &info2, NULL,
2715                           REL234_LE, &pos);
2716     if (!below)
2717         pos = -1;
2718     above = index234(fs->fonts_by_selorder, pos+1);
2719
2720     /*
2721      * See if we've found it exactly, which is an easy special
2722      * case. If we have, it'll be in `below' and not `above',
2723      * because we did a REL234_LE rather than REL234_LT search.
2724      */
2725     if (below && !fontinfo_selorder_compare(&info2, below))
2726         return below;
2727
2728     /*
2729      * Now we've either found two suitable fonts, one smaller and
2730      * one larger, or we're at one or other extreme end of the
2731      * scale. Find out which, by NULLing out either of below and
2732      * above if it differs from this one in any respect but size
2733      * (and the disambiguating index field). Bear in mind, also,
2734      * that either one might _already_ be NULL if we're at the
2735      * extreme ends of the font list.
2736      */
2737     if (below) {
2738         info2.size = below->size;
2739         info2.index = below->index;
2740         if (fontinfo_selorder_compare(&info2, below))
2741             below = NULL;
2742     }
2743     if (above) {
2744         info2.size = above->size;
2745         info2.index = above->index;
2746         if (fontinfo_selorder_compare(&info2, above))
2747             above = NULL;
2748     }
2749
2750     /*
2751      * Now return whichever of above and below is non-NULL, if
2752      * that's unambiguous.
2753      */
2754     if (!above)
2755         return below;
2756     if (!below)
2757         return above;
2758
2759     /*
2760      * And now we really do have to make a choice about whether to
2761      * round up or down. We'll do it by rounding to nearest,
2762      * breaking ties by rounding up.
2763      */
2764     if (above->size - fs->intendedsize <= fs->intendedsize - below->size)
2765         return above;
2766     else
2767         return below;
2768 }
2769
2770 static void family_changed(GtkTreeSelection *treeselection, gpointer data)
2771 {
2772     unifontsel_internal *fs = (unifontsel_internal *)data;
2773     GtkTreeModel *treemodel;
2774     GtkTreeIter treeiter;
2775     int minval;
2776     fontinfo *info;
2777
2778     if (fs->inhibit_response)          /* we made this change ourselves */
2779         return;
2780
2781     if (!gtk_tree_selection_get_selected(treeselection, &treemodel, &treeiter))
2782         return;
2783
2784     gtk_tree_model_get(treemodel, &treeiter, 1, &minval, -1);
2785     info = (fontinfo *)index234(fs->fonts_by_selorder, minval);
2786     info = update_for_intended_size(fs, info);
2787     if (!info)
2788         return; /* _shouldn't_ happen unless font list is completely funted */
2789     if (!info->size)
2790         fs->selsize = fs->intendedsize;   /* font is scalable */
2791     unifontsel_select_font(fs, info, info->size ? info->size : fs->selsize,
2792                            1, FALSE);
2793 }
2794
2795 static void style_changed(GtkTreeSelection *treeselection, gpointer data)
2796 {
2797     unifontsel_internal *fs = (unifontsel_internal *)data;
2798     GtkTreeModel *treemodel;
2799     GtkTreeIter treeiter;
2800     int minval;
2801     fontinfo *info;
2802
2803     if (fs->inhibit_response)          /* we made this change ourselves */
2804         return;
2805
2806     if (!gtk_tree_selection_get_selected(treeselection, &treemodel, &treeiter))
2807         return;
2808
2809     gtk_tree_model_get(treemodel, &treeiter, 1, &minval, -1);
2810     if (minval < 0)
2811         return;                    /* somehow a charset heading got clicked */
2812     info = (fontinfo *)index234(fs->fonts_by_selorder, minval);
2813     info = update_for_intended_size(fs, info);
2814     if (!info)
2815         return; /* _shouldn't_ happen unless font list is completely funted */
2816     if (!info->size)
2817         fs->selsize = fs->intendedsize;   /* font is scalable */
2818     unifontsel_select_font(fs, info, info->size ? info->size : fs->selsize,
2819                            2, FALSE);
2820 }
2821
2822 static void size_changed(GtkTreeSelection *treeselection, gpointer data)
2823 {
2824     unifontsel_internal *fs = (unifontsel_internal *)data;
2825     GtkTreeModel *treemodel;
2826     GtkTreeIter treeiter;
2827     int minval, size;
2828     fontinfo *info;
2829
2830     if (fs->inhibit_response)          /* we made this change ourselves */
2831         return;
2832
2833     if (!gtk_tree_selection_get_selected(treeselection, &treemodel, &treeiter))
2834         return;
2835
2836     gtk_tree_model_get(treemodel, &treeiter, 1, &minval, 2, &size, -1);
2837     info = (fontinfo *)index234(fs->fonts_by_selorder, minval);
2838     unifontsel_select_font(fs, info, info->size ? info->size : size, 3, TRUE);
2839 }
2840
2841 static void size_entry_changed(GtkEditable *ed, gpointer data)
2842 {
2843     unifontsel_internal *fs = (unifontsel_internal *)data;
2844     const char *text;
2845     int size;
2846
2847     if (fs->inhibit_response)          /* we made this change ourselves */
2848         return;
2849
2850     text = gtk_entry_get_text(GTK_ENTRY(ed));
2851     size = atoi(text);
2852
2853     if (size > 0) {
2854         assert(fs->selected->size == 0);
2855         unifontsel_select_font(fs, fs->selected, size, 3, TRUE);
2856     }
2857 }
2858
2859 static void alias_resolve(GtkTreeView *treeview, GtkTreePath *path,
2860                           GtkTreeViewColumn *column, gpointer data)
2861 {
2862     unifontsel_internal *fs = (unifontsel_internal *)data;
2863     GtkTreeIter iter;
2864     int minval, newsize;
2865     fontinfo *info, *newinfo;
2866     char *newname;
2867
2868     if (fs->inhibit_response)          /* we made this change ourselves */
2869         return;
2870
2871     gtk_tree_model_get_iter(GTK_TREE_MODEL(fs->family_model), &iter, path);
2872     gtk_tree_model_get(GTK_TREE_MODEL(fs->family_model), &iter, 1,&minval, -1);
2873     info = (fontinfo *)index234(fs->fonts_by_selorder, minval);
2874     if (info) {
2875         int flags;
2876         struct fontinfo_realname_find f;
2877
2878         newname = info->fontclass->canonify_fontname
2879             (GTK_WIDGET(fs->u.window), info->realname, &newsize, &flags, TRUE);
2880
2881         f.realname = newname;
2882         f.flags = flags;
2883         newinfo = find234(fs->fonts_by_realname, &f, fontinfo_realname_find);
2884
2885         sfree(newname);
2886         if (!newinfo)
2887             return;                    /* font name not in our index */
2888         if (newinfo == info)
2889             return;   /* didn't change under canonification => not an alias */
2890         unifontsel_select_font(fs, newinfo,
2891                                newinfo->size ? newinfo->size : newsize,
2892                                1, TRUE);
2893     }
2894 }
2895
2896 #if GTK_CHECK_VERSION(3,0,0)
2897 static gint unifontsel_draw_area(GtkWidget *widget, cairo_t *cr, gpointer data)
2898 {
2899     unifontsel_internal *fs = (unifontsel_internal *)data;
2900     unifont_drawctx dctx;
2901
2902     dctx.type = DRAWTYPE_CAIRO;
2903     dctx.u.cairo.widget = widget;
2904     dctx.u.cairo.cr = cr;
2905     unifontsel_draw_preview_text_inner(&dctx, fs);
2906
2907     return TRUE;
2908 }
2909 #else
2910 static gint unifontsel_expose_area(GtkWidget *widget, GdkEventExpose *event,
2911                                    gpointer data)
2912 {
2913     unifontsel_internal *fs = (unifontsel_internal *)data;
2914
2915 #ifndef NO_BACKING_PIXMAPS
2916     if (fs->preview_pixmap) {
2917         gdk_draw_pixmap(gtk_widget_get_window(widget),
2918                         (gtk_widget_get_style(widget)->fg_gc
2919                          [gtk_widget_get_state(widget)]),
2920                         fs->preview_pixmap,
2921                         event->area.x, event->area.y,
2922                         event->area.x, event->area.y,
2923                         event->area.width, event->area.height);
2924     }
2925 #else
2926     unifontsel_draw_preview_text(fs);
2927 #endif
2928
2929     return TRUE;
2930 }
2931 #endif
2932
2933 static gint unifontsel_configure_area(GtkWidget *widget,
2934                                       GdkEventConfigure *event, gpointer data)
2935 {
2936 #ifndef NO_BACKING_PIXMAPS
2937     unifontsel_internal *fs = (unifontsel_internal *)data;
2938     int ox, oy, nx, ny, x, y;
2939
2940     /*
2941      * Enlarge the pixmap, but never shrink it.
2942      */
2943     ox = fs->preview_width;
2944     oy = fs->preview_height;
2945     x = event->width;
2946     y = event->height;
2947     if (x > ox || y > oy) {
2948         if (fs->preview_pixmap)
2949             gdk_pixmap_unref(fs->preview_pixmap);
2950         
2951         nx = (x > ox ? x : ox);
2952         ny = (y > oy ? y : oy);
2953         fs->preview_pixmap = gdk_pixmap_new(gtk_widget_get_window(widget),
2954                                             nx, ny, -1);
2955         fs->preview_width = nx;
2956         fs->preview_height = ny;
2957
2958         unifontsel_draw_preview_text(fs);
2959     }
2960 #endif
2961
2962     gdk_window_invalidate_rect(gtk_widget_get_window(widget), NULL, FALSE);
2963
2964     return TRUE;
2965 }
2966
2967 unifontsel *unifontsel_new(const char *wintitle)
2968 {
2969     unifontsel_internal *fs = snew(unifontsel_internal);
2970     GtkWidget *table, *label, *w, *ww, *scroll;
2971     GtkListStore *model;
2972     GtkTreeViewColumn *column;
2973     int lists_height, preview_height, font_width, style_width, size_width;
2974     int i;
2975
2976     fs->inhibit_response = FALSE;
2977     fs->selected = NULL;
2978
2979     {
2980         int width, height;
2981
2982         /*
2983          * Invent some magic size constants.
2984          */
2985         get_label_text_dimensions("Quite Long Font Name (Foundry)",
2986                                   &width, &height);
2987         font_width = width;
2988         lists_height = 14 * height;
2989         preview_height = 5 * height;
2990
2991         get_label_text_dimensions("Italic Extra Condensed", &width, &height);
2992         style_width = width;
2993
2994         get_label_text_dimensions("48000", &width, &height);
2995         size_width = width;
2996     }
2997
2998     /*
2999      * Create the dialog box and initialise the user-visible
3000      * fields in the returned structure.
3001      */
3002     fs->u.user_data = NULL;
3003     fs->u.window = GTK_WINDOW(gtk_dialog_new());
3004     gtk_window_set_title(fs->u.window, wintitle);
3005     fs->u.cancel_button = gtk_dialog_add_button
3006         (GTK_DIALOG(fs->u.window), STANDARD_CANCEL_LABEL, GTK_RESPONSE_CANCEL);
3007     fs->u.ok_button = gtk_dialog_add_button
3008         (GTK_DIALOG(fs->u.window), STANDARD_OK_LABEL, GTK_RESPONSE_OK);
3009     gtk_widget_grab_default(fs->u.ok_button);
3010
3011     /*
3012      * Now set up the internal fields, including in particular all
3013      * the controls that actually allow the user to select fonts.
3014      */
3015 #if GTK_CHECK_VERSION(3,0,0)
3016     table = gtk_grid_new();
3017     gtk_grid_set_column_spacing(GTK_GRID(table), 8);
3018 #else
3019     table = gtk_table_new(8, 3, FALSE);
3020     gtk_table_set_col_spacings(GTK_TABLE(table), 8);
3021 #endif
3022     gtk_widget_show(table);
3023
3024 #if GTK_CHECK_VERSION(3,0,0)
3025     /* GtkAlignment has become deprecated and we use the "margin"
3026      * property */
3027     w = table;
3028     g_object_set(G_OBJECT(w), "margin", 8, (const char *)NULL);
3029 #elif GTK_CHECK_VERSION(2,4,0)
3030     /* GtkAlignment seems to be the simplest way to put padding round things */
3031     w = gtk_alignment_new(0, 0, 1, 1);
3032     gtk_alignment_set_padding(GTK_ALIGNMENT(w), 8, 8, 8, 8);
3033     gtk_container_add(GTK_CONTAINER(w), table);
3034     gtk_widget_show(w);
3035 #else
3036     /* In GTK < 2.4, even that isn't available */
3037     w = table;
3038 #endif
3039
3040     gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area
3041                                (GTK_DIALOG(fs->u.window))),
3042                        w, TRUE, TRUE, 0);
3043
3044     label = gtk_label_new_with_mnemonic("_Font:");
3045     gtk_widget_show(label);
3046     align_label_left(GTK_LABEL(label));
3047 #if GTK_CHECK_VERSION(3,0,0)
3048     gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
3049     g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL);
3050 #else
3051     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
3052 #endif
3053
3054     /*
3055      * The Font list box displays only a string, but additionally
3056      * stores two integers which give the limits within the
3057      * tree234 of the font entries covered by this list entry.
3058      */
3059     model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
3060     w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
3061     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE);
3062     gtk_label_set_mnemonic_widget(GTK_LABEL(label), w);
3063     gtk_widget_show(w);
3064     column = gtk_tree_view_column_new_with_attributes
3065         ("Font", gtk_cell_renderer_text_new(),
3066          "text", 0, (char *)NULL);
3067     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
3068     gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
3069     g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(w))),
3070                      "changed", G_CALLBACK(family_changed), fs);
3071     g_signal_connect(G_OBJECT(w), "row-activated",
3072                      G_CALLBACK(alias_resolve), fs);
3073
3074     scroll = gtk_scrolled_window_new(NULL, NULL);
3075     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
3076                                         GTK_SHADOW_IN);
3077     gtk_container_add(GTK_CONTAINER(scroll), w);
3078     gtk_widget_show(scroll);
3079     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
3080                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3081     gtk_widget_set_size_request(scroll, font_width, lists_height);
3082 #if GTK_CHECK_VERSION(3,0,0)
3083     gtk_grid_attach(GTK_GRID(table), scroll, 0, 1, 1, 2);
3084     g_object_set(G_OBJECT(scroll), "expand", TRUE, (const char *)NULL);
3085 #else
3086     gtk_table_attach(GTK_TABLE(table), scroll, 0, 1, 1, 3, GTK_FILL,
3087                      GTK_EXPAND | GTK_FILL, 0, 0);
3088 #endif
3089     fs->family_model = model;
3090     fs->family_list = w;
3091
3092     label = gtk_label_new_with_mnemonic("_Style:");
3093     gtk_widget_show(label);
3094     align_label_left(GTK_LABEL(label));
3095 #if GTK_CHECK_VERSION(3,0,0)
3096     gtk_grid_attach(GTK_GRID(table), label, 1, 0, 1, 1);
3097     g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL);
3098 #else
3099     gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
3100 #endif
3101
3102     /*
3103      * The Style list box can contain insensitive elements
3104      * (character set headings for server-side fonts), so we add
3105      * an extra column to the list store to hold that information.
3106      */
3107     model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3108                                G_TYPE_BOOLEAN);
3109     w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
3110     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE);
3111     gtk_label_set_mnemonic_widget(GTK_LABEL(label), w);
3112     gtk_widget_show(w);
3113     column = gtk_tree_view_column_new_with_attributes
3114         ("Style", gtk_cell_renderer_text_new(),
3115          "text", 0, "sensitive", 3, (char *)NULL);
3116     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
3117     gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
3118     g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(w))),
3119                      "changed", G_CALLBACK(style_changed), fs);
3120
3121     scroll = gtk_scrolled_window_new(NULL, NULL);
3122     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
3123                                         GTK_SHADOW_IN);
3124     gtk_container_add(GTK_CONTAINER(scroll), w);
3125     gtk_widget_show(scroll);
3126     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
3127                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3128     gtk_widget_set_size_request(scroll, style_width, lists_height);
3129 #if GTK_CHECK_VERSION(3,0,0)
3130     gtk_grid_attach(GTK_GRID(table), scroll, 1, 1, 1, 2);
3131     g_object_set(G_OBJECT(scroll), "expand", TRUE, (const char *)NULL);
3132 #else
3133     gtk_table_attach(GTK_TABLE(table), scroll, 1, 2, 1, 3, GTK_FILL,
3134                      GTK_EXPAND | GTK_FILL, 0, 0);
3135 #endif
3136     fs->style_model = model;
3137     fs->style_list = w;
3138
3139     label = gtk_label_new_with_mnemonic("Si_ze:");
3140     gtk_widget_show(label);
3141     align_label_left(GTK_LABEL(label));
3142 #if GTK_CHECK_VERSION(3,0,0)
3143     gtk_grid_attach(GTK_GRID(table), label, 2, 0, 1, 1);
3144     g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL);
3145 #else
3146     gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
3147 #endif
3148
3149     /*
3150      * The Size label attaches primarily to a text input box so
3151      * that the user can select a size of their choice. The list
3152      * of available sizes is secondary.
3153      */
3154     fs->size_entry = w = gtk_entry_new();
3155     gtk_label_set_mnemonic_widget(GTK_LABEL(label), w);
3156     gtk_widget_set_size_request(w, size_width, -1);
3157     gtk_widget_show(w);
3158 #if GTK_CHECK_VERSION(3,0,0)
3159     gtk_grid_attach(GTK_GRID(table), w, 2, 1, 1, 1);
3160     g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3161 #else
3162     gtk_table_attach(GTK_TABLE(table), w, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
3163 #endif
3164     g_signal_connect(G_OBJECT(w), "changed", G_CALLBACK(size_entry_changed),
3165                      fs);
3166
3167     model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
3168     w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
3169     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE);
3170     gtk_widget_show(w);
3171     column = gtk_tree_view_column_new_with_attributes
3172         ("Size", gtk_cell_renderer_text_new(),
3173          "text", 0, (char *)NULL);
3174     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
3175     gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
3176     g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(w))),
3177                      "changed", G_CALLBACK(size_changed), fs);
3178
3179     scroll = gtk_scrolled_window_new(NULL, NULL);
3180     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
3181                                         GTK_SHADOW_IN);
3182     gtk_container_add(GTK_CONTAINER(scroll), w);
3183     gtk_widget_show(scroll);
3184     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
3185                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3186 #if GTK_CHECK_VERSION(3,0,0)
3187     gtk_grid_attach(GTK_GRID(table), scroll, 2, 2, 1, 1);
3188     g_object_set(G_OBJECT(scroll), "expand", TRUE, (const char *)NULL);
3189 #else
3190     gtk_table_attach(GTK_TABLE(table), scroll, 2, 3, 2, 3, GTK_FILL,
3191                      GTK_EXPAND | GTK_FILL, 0, 0);
3192 #endif
3193     fs->size_model = model;
3194     fs->size_list = w;
3195
3196     /*
3197      * Preview widget.
3198      */
3199     fs->preview_area = gtk_drawing_area_new();
3200 #ifndef NO_BACKING_PIXMAPS
3201     fs->preview_pixmap = NULL;
3202 #endif
3203     fs->preview_width = 0;
3204     fs->preview_height = 0;
3205     fs->preview_fg.pixel = fs->preview_bg.pixel = 0;
3206     fs->preview_fg.red = fs->preview_fg.green = fs->preview_fg.blue = 0x0000;
3207     fs->preview_bg.red = fs->preview_bg.green = fs->preview_bg.blue = 0xFFFF;
3208 #if !GTK_CHECK_VERSION(3,0,0)
3209     gdk_colormap_alloc_color(gdk_colormap_get_system(), &fs->preview_fg,
3210                              FALSE, FALSE);
3211     gdk_colormap_alloc_color(gdk_colormap_get_system(), &fs->preview_bg,
3212                              FALSE, FALSE);
3213 #endif
3214 #if GTK_CHECK_VERSION(3,0,0)
3215     g_signal_connect(G_OBJECT(fs->preview_area), "draw",
3216                      G_CALLBACK(unifontsel_draw_area), fs);
3217 #else
3218     g_signal_connect(G_OBJECT(fs->preview_area), "expose_event",
3219                      G_CALLBACK(unifontsel_expose_area), fs);
3220 #endif
3221     g_signal_connect(G_OBJECT(fs->preview_area), "configure_event",
3222                      G_CALLBACK(unifontsel_configure_area), fs);
3223     gtk_widget_set_size_request(fs->preview_area, 1, preview_height);
3224     gtk_widget_show(fs->preview_area);
3225     ww = fs->preview_area;
3226     w = gtk_frame_new(NULL);
3227     gtk_container_add(GTK_CONTAINER(w), ww);
3228     gtk_widget_show(w);
3229
3230 #if GTK_CHECK_VERSION(3,0,0)
3231     /* GtkAlignment has become deprecated and we use the "margin"
3232      * property */
3233     g_object_set(G_OBJECT(w), "margin", 8, (const char *)NULL);
3234 #elif GTK_CHECK_VERSION(2,4,0)
3235     ww = w;
3236     /* GtkAlignment seems to be the simplest way to put padding round things */
3237     w = gtk_alignment_new(0, 0, 1, 1);
3238     gtk_alignment_set_padding(GTK_ALIGNMENT(w), 8, 8, 8, 8);
3239     gtk_container_add(GTK_CONTAINER(w), ww);
3240     gtk_widget_show(w);
3241 #endif
3242
3243     ww = w;
3244     w = gtk_frame_new("Preview of font");
3245     gtk_container_add(GTK_CONTAINER(w), ww);
3246     gtk_widget_show(w);
3247 #if GTK_CHECK_VERSION(3,0,0)
3248     gtk_grid_attach(GTK_GRID(table), w, 0, 3, 3, 1);
3249     g_object_set(G_OBJECT(w), "expand", TRUE, (const char *)NULL);
3250 #else
3251     gtk_table_attach(GTK_TABLE(table), w, 0, 3, 3, 4,
3252                      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 8);
3253 #endif
3254
3255     /*
3256      * We only provide the checkboxes for client- and server-side
3257      * fonts if we have the X11 back end available, because that's the
3258      * only situation in which more than one class of font is
3259      * available anyway.
3260      */
3261     fs->n_filter_buttons = 0;
3262 #ifndef NOT_X_WINDOWS
3263     w = gtk_check_button_new_with_label("Show client-side fonts");
3264     g_object_set_data(G_OBJECT(w), "user-data",
3265                       GINT_TO_POINTER(FONTFLAG_CLIENTSIDE));
3266     g_signal_connect(G_OBJECT(w), "toggled",
3267                      G_CALLBACK(unifontsel_button_toggled), fs);
3268     gtk_widget_show(w);
3269     fs->filter_buttons[fs->n_filter_buttons++] = w;
3270 #if GTK_CHECK_VERSION(3,0,0)
3271     gtk_grid_attach(GTK_GRID(table), w, 0, 4, 3, 1);
3272     g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3273 #else
3274     gtk_table_attach(GTK_TABLE(table), w, 0, 3, 4, 5, GTK_FILL, 0, 0, 0);
3275 #endif
3276     w = gtk_check_button_new_with_label("Show server-side fonts");
3277     g_object_set_data(G_OBJECT(w), "user-data",
3278                       GINT_TO_POINTER(FONTFLAG_SERVERSIDE));
3279     g_signal_connect(G_OBJECT(w), "toggled",
3280                      G_CALLBACK(unifontsel_button_toggled), fs);
3281     gtk_widget_show(w);
3282     fs->filter_buttons[fs->n_filter_buttons++] = w;
3283 #if GTK_CHECK_VERSION(3,0,0)
3284     gtk_grid_attach(GTK_GRID(table), w, 0, 5, 3, 1);
3285     g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3286 #else
3287     gtk_table_attach(GTK_TABLE(table), w, 0, 3, 5, 6, GTK_FILL, 0, 0, 0);
3288 #endif
3289     w = gtk_check_button_new_with_label("Show server-side font aliases");
3290     g_object_set_data(G_OBJECT(w), "user-data",
3291                       GINT_TO_POINTER(FONTFLAG_SERVERALIAS));
3292     g_signal_connect(G_OBJECT(w), "toggled",
3293                      G_CALLBACK(unifontsel_button_toggled), fs);
3294     gtk_widget_show(w);
3295     fs->filter_buttons[fs->n_filter_buttons++] = w;
3296 #if GTK_CHECK_VERSION(3,0,0)
3297     gtk_grid_attach(GTK_GRID(table), w, 0, 6, 3, 1);
3298     g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3299 #else
3300     gtk_table_attach(GTK_TABLE(table), w, 0, 3, 6, 7, GTK_FILL, 0, 0, 0);
3301 #endif
3302 #endif /* NOT_X_WINDOWS */
3303     w = gtk_check_button_new_with_label("Show non-monospaced fonts");
3304     g_object_set_data(G_OBJECT(w), "user-data",
3305                       GINT_TO_POINTER(FONTFLAG_NONMONOSPACED));
3306     g_signal_connect(G_OBJECT(w), "toggled",
3307                      G_CALLBACK(unifontsel_button_toggled), fs);
3308     gtk_widget_show(w);
3309     fs->filter_buttons[fs->n_filter_buttons++] = w;
3310 #if GTK_CHECK_VERSION(3,0,0)
3311     gtk_grid_attach(GTK_GRID(table), w, 0, 7, 3, 1);
3312     g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3313 #else
3314     gtk_table_attach(GTK_TABLE(table), w, 0, 3, 7, 8, GTK_FILL, 0, 0, 0);
3315 #endif
3316
3317     assert(fs->n_filter_buttons <= lenof(fs->filter_buttons));
3318     fs->filter_flags = FONTFLAG_CLIENTSIDE | FONTFLAG_SERVERSIDE |
3319         FONTFLAG_SERVERALIAS;
3320     unifontsel_set_filter_buttons(fs);
3321
3322     /*
3323      * Go and find all the font names, and set up our master font
3324      * list.
3325      */
3326     fs->fonts_by_realname = newtree234(fontinfo_realname_compare);
3327     fs->fonts_by_selorder = newtree234(fontinfo_selorder_compare);
3328     for (i = 0; i < lenof(unifont_types); i++)
3329         unifont_types[i]->enum_fonts(GTK_WIDGET(fs->u.window),
3330                                      unifontsel_add_entry, fs);
3331
3332     /*
3333      * And set up the initial font names list.
3334      */
3335     unifontsel_setup_familylist(fs);
3336
3337     fs->selsize = fs->intendedsize = 13;   /* random default */
3338     gtk_widget_set_sensitive(fs->u.ok_button, FALSE);
3339
3340     return (unifontsel *)fs;
3341 }
3342
3343 void unifontsel_destroy(unifontsel *fontsel)
3344 {
3345     unifontsel_internal *fs = (unifontsel_internal *)fontsel;
3346     fontinfo *info;
3347
3348 #ifndef NO_BACKING_PIXMAPS
3349     if (fs->preview_pixmap)
3350         gdk_pixmap_unref(fs->preview_pixmap);
3351 #endif
3352
3353     freetree234(fs->fonts_by_selorder);
3354     while ((info = delpos234(fs->fonts_by_realname, 0)) != NULL)
3355         sfree(info);
3356     freetree234(fs->fonts_by_realname);
3357
3358     gtk_widget_destroy(GTK_WIDGET(fs->u.window));
3359     sfree(fs);
3360 }
3361
3362 void unifontsel_set_name(unifontsel *fontsel, const char *fontname)
3363 {
3364     unifontsel_internal *fs = (unifontsel_internal *)fontsel;
3365     int i, start, end, size, flags;
3366     const char *fontname2 = NULL;
3367     fontinfo *info;
3368
3369     /*
3370      * Provide a default if given an empty or null font name.
3371      */
3372     if (!fontname || !*fontname)
3373         fontname = DEFAULT_GTK_FONT;
3374
3375     /*
3376      * Call the canonify_fontname function.
3377      */
3378     fontname = unifont_do_prefix(fontname, &start, &end);
3379     for (i = start; i < end; i++) {
3380         fontname2 = unifont_types[i]->canonify_fontname
3381             (GTK_WIDGET(fs->u.window), fontname, &size, &flags, FALSE);
3382         if (fontname2)
3383             break;
3384     }
3385     if (i == end)
3386         return;                        /* font name not recognised */
3387
3388     /*
3389      * Now look up the canonified font name in our index.
3390      */
3391     {
3392         struct fontinfo_realname_find f;
3393         f.realname = fontname2;
3394         f.flags = flags;
3395         info = find234(fs->fonts_by_realname, &f, fontinfo_realname_find);
3396     }
3397
3398     /*
3399      * If we've found the font, and its size field is either
3400      * correct or zero (the latter indicating a scalable font),
3401      * then we're done. Otherwise, try looking up the original
3402      * font name instead.
3403      */
3404     if (!info || (info->size != size && info->size != 0)) {
3405         struct fontinfo_realname_find f;
3406         f.realname = fontname;
3407         f.flags = flags;
3408
3409         info = find234(fs->fonts_by_realname, &f, fontinfo_realname_find);
3410         if (!info || info->size != size)
3411             return;                    /* font name not in our index */
3412     }
3413
3414     /*
3415      * Now we've got a fontinfo structure and a font size, so we
3416      * know everything we need to fill in all the fields in the
3417      * dialog.
3418      */
3419     unifontsel_select_font(fs, info, size, 0, TRUE);
3420 }
3421
3422 char *unifontsel_get_name(unifontsel *fontsel)
3423 {
3424     unifontsel_internal *fs = (unifontsel_internal *)fontsel;
3425     char *name;
3426
3427     if (!fs->selected)
3428         return NULL;
3429
3430     if (fs->selected->size == 0) {
3431         name = fs->selected->fontclass->scale_fontname
3432             (GTK_WIDGET(fs->u.window), fs->selected->realname, fs->selsize);
3433         if (name) {
3434             char *ret = dupcat(fs->selected->fontclass->prefix, ":",
3435                                name, NULL);
3436             sfree(name);
3437             return ret;
3438         }
3439     }
3440
3441     return dupcat(fs->selected->fontclass->prefix, ":",
3442                   fs->selected->realname, NULL);
3443 }
3444
3445 #endif /* GTK_CHECK_VERSION(2,0,0) */