2 * Unified font management for GTK.
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
17 #if !GTK_CHECK_VERSION(3,0,0)
18 #include <gdk/gdkkeysyms.h>
21 #define MAY_REFER_TO_GTK_IN_HEADERS
25 #include "gtkcompat.h"
32 #include <X11/Xutil.h>
33 #include <X11/Xatom.h>
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.
44 #if !GLIB_CHECK_VERSION(1,3,7)
45 #define g_ascii_strcasecmp g_strcasecmp
46 #define g_ascii_strncasecmp g_strncasecmp
50 * Ad-hoc vtable mechanism to allow font structures to be
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.
60 #define FONTFLAG_CLIENTSIDE 0x0001
61 #define FONTFLAG_SERVERSIDE 0x0002
62 #define FONTFLAG_SERVERALIAS 0x0004
63 #define FONTFLAG_NONMONOSPACED 0x0008
65 #define FONTFLAG_SORT_MASK 0x0007 /* used to disambiguate font families */
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,
71 const struct unifont_vtable *fontclass);
73 struct unifont_vtable {
75 * `Methods' of the `class'.
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 (*draw_combining)(unifont_drawctx *ctx, unifont *font,
87 int x, int y, const wchar_t *string, int len,
88 int wide, int bold, int cellwidth);
89 void (*enum_fonts)(GtkWidget *widget,
90 fontsel_add_entry callback, void *callback_ctx);
91 char *(*canonify_fontname)(GtkWidget *widget, const char *name, int *size,
92 int *flags, int resolve_aliases);
93 char *(*scale_fontname)(GtkWidget *widget, const char *name, int size);
96 * `Static data members' of the `class'.
101 #ifndef NOT_X_WINDOWS
103 /* ----------------------------------------------------------------------
104 * X11 font implementation, directly using Xlib calls. Conditioned out
105 * if X11 fonts aren't available at all (e.g. building with GTK3 for a
106 * back end other than X).
109 static int x11font_has_glyph(unifont *font, wchar_t glyph);
110 static void x11font_draw_text(unifont_drawctx *ctx, unifont *font,
111 int x, int y, const wchar_t *string, int len,
112 int wide, int bold, int cellwidth);
113 static void x11font_draw_combining(unifont_drawctx *ctx, unifont *font,
114 int x, int y, const wchar_t *string,
115 int len, int wide, int bold, int cellwidth);
116 static unifont *x11font_create(GtkWidget *widget, const char *name,
118 int shadowoffset, int shadowalways);
119 static void x11font_destroy(unifont *font);
120 static void x11font_enum_fonts(GtkWidget *widget,
121 fontsel_add_entry callback, void *callback_ctx);
122 static char *x11font_canonify_fontname(GtkWidget *widget, const char *name,
123 int *size, int *flags,
124 int resolve_aliases);
125 static char *x11font_scale_fontname(GtkWidget *widget, const char *name,
128 #ifdef DRAW_TEXT_CAIRO
129 struct cairo_cached_glyph {
130 cairo_surface_t *surface;
131 unsigned char *bitmap;
136 * Structure storing a single physical XFontStruct, plus associated
139 typedef struct x11font_individual {
140 /* The XFontStruct itself. */
144 * The `allocated' flag indicates whether we've tried to fetch
145 * this subfont already (thus distinguishing xfs==NULL because we
146 * haven't tried yet from xfs==NULL because we tried and failed,
147 * so that we don't keep trying and failing subsequently).
151 #ifdef DRAW_TEXT_CAIRO
153 * A cache of glyph bitmaps downloaded from the X server when
154 * we're in Cairo rendering mode. If glyphcache itself is
155 * non-NULL, then entries in [0,nglyphs) are expected to be
156 * initialised to either NULL or a bitmap pointer.
158 struct cairo_cached_glyph *glyphcache;
162 * X server paraphernalia for actually downloading the glyphs.
166 int pixwidth, pixheight, pixoriginx, pixoriginy;
169 * Paraphernalia for loading the resulting bitmaps into Cairo.
171 int rowsize, allsize, indexflip;
174 } x11font_individual;
179 * Individual physical X fonts. We store a number of these, for
180 * automatically guessed bold and wide variants.
182 x11font_individual fonts[4];
184 * `sixteen_bit' is true iff the font object is indexed by
185 * values larger than a byte. That is, this flag tells us
186 * whether we use XDrawString or XDrawString16, etc.
190 * `variable' is true iff the font is non-fixed-pitch. This
191 * enables some code which takes greater care over character
192 * positioning during text drawing.
196 * real_charset is the charset used when translating text into the
197 * font's internal encoding inside draw_text(). This need not be
198 * the same as the public_charset provided to the client; for
199 * example, public_charset might be CS_ISO8859_1 while
200 * real_charset is CS_ISO8859_1_X11.
204 * Data passed in to unifont_create().
206 int wide, bold, shadowoffset, shadowalways;
209 static const struct unifont_vtable x11font_vtable = {
211 NULL, /* no fallback fonts in X11 */
215 x11font_draw_combining,
217 x11font_canonify_fontname,
218 x11font_scale_fontname,
222 #define XLFD_STRING_PARTS_LIST(S,I) \
235 S(charset_registry) \
236 S(charset_encoding) \
239 struct xlfd_decomposed {
240 #define STR_FIELD(f) const char *f;
241 #define INT_FIELD(f) int f;
242 XLFD_STRING_PARTS_LIST(STR_FIELD, INT_FIELD)
247 static struct xlfd_decomposed *xlfd_decompose(const char *xlfd)
250 char *p, *components[14];
251 struct xlfd_decomposed *dec;
257 mem = smalloc(sizeof(struct xlfd_decomposed) + strlen(xlfd) + 1);
258 p = ((char *)mem) + sizeof(struct xlfd_decomposed);
260 dec = (struct xlfd_decomposed *)mem;
262 for (i = 0; i < 14; i++) {
264 /* Malformed XLFD: not enough '-' */
270 p += strcspn(p, "-");
273 /* Malformed XLFD: too many '-' */
279 #define STORE_STR(f) dec->f = components[i++];
280 #define STORE_INT(f) dec->f = atoi(components[i++]);
281 XLFD_STRING_PARTS_LIST(STORE_STR, STORE_INT)
288 static char *xlfd_recompose(const struct xlfd_decomposed *dec)
290 #define FMT_STR(f) "-%s"
291 #define ARG_STR(f) , dec->f
292 #define FMT_INT(f) "-%d"
293 #define ARG_INT(f) , dec->f
294 return dupprintf(XLFD_STRING_PARTS_LIST(FMT_STR, FMT_INT)
295 XLFD_STRING_PARTS_LIST(ARG_STR, ARG_INT));
302 static char *x11_guess_derived_font_name(XFontStruct *xfs, int bold, int wide)
304 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
305 Atom fontprop = XInternAtom(disp, "FONT", False);
307 if (XGetFontProperty(xfs, fontprop, &ret)) {
308 char *name = XGetAtomName(disp, (Atom)ret);
309 struct xlfd_decomposed *xlfd = xlfd_decompose(name);
314 xlfd->weight_name = "bold";
317 /* Width name obviously may have changed. */
318 /* Additional style may now become e.g. `ja' or `ko'. */
319 xlfd->setwidth_name = xlfd->add_style_name = "*";
321 /* Expect to double the average width. */
322 xlfd->average_width *= 2;
326 char *ret = xlfd_recompose(xlfd);
334 static int x11_font_width(XFontStruct *xfs, int sixteen_bit)
340 return XTextWidth16(xfs, &space, 1);
342 return XTextWidth(xfs, "0", 1);
346 static const XCharStruct *x11_char_struct(XFontStruct *xfs,
347 int byte1, int byte2)
352 * The man page for XQueryFont is rather confusing about how the
353 * per_char array in the XFontStruct is laid out, because it gives
354 * formulae for determining the two-byte X character code _from_
355 * an index into the per_char array. Going the other way, it's
358 * The valid character codes have byte1 between min_byte1 and
359 * max_byte1 inclusive, and byte2 between min_char_or_byte2 and
360 * max_char_or_byte2 inclusive. This gives a rectangle of size
361 * (max_byte2-min_byte1+1) by
362 * (max_char_or_byte2-min_char_or_byte2+1), which is precisely the
363 * rectangle encoded in the per_char array. Hence, given a
364 * character code which is valid in the sense that it falls
365 * somewhere in that rectangle, its index in per_char is given by
368 * x = byte2 - min_char_or_byte2
369 * y = byte1 - min_byte1
370 * index = y * (max_char_or_byte2-min_char_or_byte2+1) + x
372 * If min_byte1 and min_byte2 are both zero, that's a special case
373 * which can be treated as if min_byte2 was 1 instead, i.e. the
374 * per_char array just runs from min_char_or_byte2 to
375 * max_char_or_byte2 inclusive, and byte1 should always be zero.
378 if (byte2 < xfs->min_char_or_byte2 || byte2 > xfs->max_char_or_byte2)
381 if (xfs->min_byte1 == 0 && xfs->max_byte1 == 0) {
382 index = byte2 - xfs->min_char_or_byte2;
384 if (byte1 < xfs->min_byte1 || byte1 > xfs->max_byte1)
386 index = ((byte2 - xfs->min_char_or_byte2) +
387 ((byte1 - xfs->min_byte1) *
388 (xfs->max_char_or_byte2 - xfs->min_char_or_byte2 + 1)));
391 if (!xfs->per_char) /* per_char NULL => everything in range exists */
392 return &xfs->max_bounds;
394 return &xfs->per_char[index];
397 static int x11_font_has_glyph(XFontStruct *xfs, int byte1, int byte2)
400 * Not to be confused with x11font_has_glyph, which is a method of
401 * the x11font 'class' and hence takes a unifont as argument. This
402 * is the low-level function which grubs about in an actual
403 * XFontStruct to see if a given glyph exists.
405 * We must do this ourselves rather than letting Xlib's
406 * XTextExtents16 do the job, because XTextExtents will helpfully
407 * substitute the font's default_char for any missing glyph and
408 * not tell us it did so, which precisely won't help us find out
409 * which glyphs _are_ missing.
411 const XCharStruct *xcs = x11_char_struct(xfs, byte1, byte2);
412 return xcs && (xcs->ascent + xcs->descent > 0 || xcs->width > 0);
415 static unifont *x11font_create(GtkWidget *widget, const char *name,
417 int shadowoffset, int shadowalways)
419 struct x11font *xfont;
421 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
422 Atom charset_registry, charset_encoding, spacing;
423 unsigned long registry_ret, encoding_ret, spacing_ret;
424 int pubcs, realcs, sixteen_bit, variable;
427 xfs = XLoadQueryFont(disp, name);
431 charset_registry = XInternAtom(disp, "CHARSET_REGISTRY", False);
432 charset_encoding = XInternAtom(disp, "CHARSET_ENCODING", False);
434 pubcs = realcs = CS_NONE;
438 if (XGetFontProperty(xfs, charset_registry, ®istry_ret) &&
439 XGetFontProperty(xfs, charset_encoding, &encoding_ret)) {
441 reg = XGetAtomName(disp, (Atom)registry_ret);
442 enc = XGetAtomName(disp, (Atom)encoding_ret);
444 char *encoding = dupcat(reg, "-", enc, NULL);
445 pubcs = realcs = charset_from_xenc(encoding);
448 * iso10646-1 is the only wide font encoding we
449 * support. In this case, we expect clients to give us
450 * UTF-8, which this module must internally convert
451 * into 16-bit Unicode.
453 if (!strcasecmp(encoding, "iso10646-1")) {
455 pubcs = realcs = CS_UTF8;
459 * Hack for X line-drawing characters: if the primary font
460 * is encoded as ISO-8859-1, and has valid glyphs in the
461 * low character positions, it is assumed that those
462 * glyphs are the VT100 line-drawing character set.
464 if (pubcs == CS_ISO8859_1) {
466 for (ch = 1; ch < 32; ch++)
467 if (!x11_font_has_glyph(xfs, 0, ch))
470 realcs = CS_ISO8859_1_X11;
477 spacing = XInternAtom(disp, "SPACING", False);
478 if (XGetFontProperty(xfs, spacing, &spacing_ret)) {
480 spc = XGetAtomName(disp, (Atom)spacing_ret);
482 if (spc && strchr("CcMm", spc[0]))
486 xfont = snew(struct x11font);
487 xfont->u.vt = &x11font_vtable;
488 xfont->u.width = x11_font_width(xfs, sixteen_bit);
489 xfont->u.ascent = xfs->ascent;
490 xfont->u.descent = xfs->descent;
491 xfont->u.height = xfont->u.ascent + xfont->u.descent;
492 xfont->u.public_charset = pubcs;
493 xfont->u.want_fallback = TRUE;
495 xfont->u.preferred_drawtype = DRAWTYPE_GDK;
496 #elif defined DRAW_TEXT_CAIRO
497 xfont->u.preferred_drawtype = DRAWTYPE_CAIRO;
499 #error No drawtype available at all
501 xfont->real_charset = realcs;
502 xfont->sixteen_bit = sixteen_bit;
503 xfont->variable = variable;
506 xfont->shadowoffset = shadowoffset;
507 xfont->shadowalways = shadowalways;
509 for (i = 0; i < lenof(xfont->fonts); i++) {
510 xfont->fonts[i].xfs = NULL;
511 xfont->fonts[i].allocated = FALSE;
512 #ifdef DRAW_TEXT_CAIRO
513 xfont->fonts[i].glyphcache = NULL;
514 xfont->fonts[i].nglyphs = 0;
515 xfont->fonts[i].pixmap = None;
516 xfont->fonts[i].gc = None;
519 xfont->fonts[0].xfs = xfs;
520 xfont->fonts[0].allocated = TRUE;
522 return (unifont *)xfont;
525 static void x11font_destroy(unifont *font)
527 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
528 struct x11font *xfont = (struct x11font *)font;
531 for (i = 0; i < lenof(xfont->fonts); i++) {
532 if (xfont->fonts[i].xfs)
533 XFreeFont(disp, xfont->fonts[i].xfs);
534 #ifdef DRAW_TEXT_CAIRO
535 if (xfont->fonts[i].gc != None)
536 XFreeGC(disp, xfont->fonts[i].gc);
537 if (xfont->fonts[i].pixmap != None)
538 XFreePixmap(disp, xfont->fonts[i].pixmap);
539 if (xfont->fonts[i].glyphcache) {
541 for (j = 0; j < xfont->fonts[i].nglyphs; j++) {
542 cairo_surface_destroy(xfont->fonts[i].glyphcache[j].surface);
543 sfree(xfont->fonts[i].glyphcache[j].bitmap);
545 sfree(xfont->fonts[i].glyphcache);
552 static void x11_alloc_subfont(struct x11font *xfont, int sfid)
554 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
555 char *derived_name = x11_guess_derived_font_name
556 (xfont->fonts[0].xfs, sfid & 1, !!(sfid & 2));
557 xfont->fonts[sfid].xfs = XLoadQueryFont(disp, derived_name);
558 xfont->fonts[sfid].allocated = TRUE;
560 /* Note that xfont->fonts[sfid].xfs may still be NULL, if XLQF failed. */
563 static int x11font_has_glyph(unifont *font, wchar_t glyph)
565 struct x11font *xfont = (struct x11font *)font;
567 if (xfont->sixteen_bit) {
569 * This X font has 16-bit character indices, which means
570 * we can directly use our Unicode input value.
572 return x11_font_has_glyph(xfont->fonts[0].xfs,
573 glyph >> 8, glyph & 0xFF);
576 * This X font has 8-bit indices, so we must convert to the
577 * appropriate character set.
580 int sblen = wc_to_mb(xfont->real_charset, 0, &glyph, 1,
581 sbstring, 2, "", NULL, NULL);
582 if (sblen == 0 || !sbstring[0])
583 return FALSE; /* not even in the charset */
585 return x11_font_has_glyph(xfont->fonts[0].xfs, 0,
586 (unsigned char)sbstring[0]);
590 #if !GTK_CHECK_VERSION(2,0,0)
591 #define GDK_DRAWABLE_XID(d) GDK_WINDOW_XWINDOW(d) /* GTK1's name for this */
592 #elif GTK_CHECK_VERSION(3,0,0)
593 #define GDK_DRAWABLE_XID(d) GDK_WINDOW_XID(d) /* GTK3's name for this */
596 static int x11font_width_16(unifont_drawctx *ctx, x11font_individual *xfi,
597 const void *vstring, int start, int length)
599 const XChar2b *string = (const XChar2b *)vstring;
600 return XTextWidth16(xfi->xfs, string+start, length);
603 static int x11font_width_8(unifont_drawctx *ctx, x11font_individual *xfi,
604 const void *vstring, int start, int length)
606 const char *string = (const char *)vstring;
607 return XTextWidth(xfi->xfs, string+start, length);
611 static void x11font_gdk_setup(unifont_drawctx *ctx, x11font_individual *xfi)
613 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
614 XSetFont(disp, GDK_GC_XGC(ctx->u.gdk.gc), xfi->xfs->fid);
617 static void x11font_gdk_draw_16(unifont_drawctx *ctx,
618 x11font_individual *xfi, int x, int y,
619 const void *vstring, int start, int length)
621 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
622 const XChar2b *string = (const XChar2b *)vstring;
623 XDrawString16(disp, GDK_DRAWABLE_XID(ctx->u.gdk.target),
624 GDK_GC_XGC(ctx->u.gdk.gc), x, y, string+start, length);
627 static void x11font_gdk_draw_8(unifont_drawctx *ctx,
628 x11font_individual *xfi, int x, int y,
629 const void *vstring, int start, int length)
631 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
632 const char *string = (const char *)vstring;
633 XDrawString(disp, GDK_DRAWABLE_XID(ctx->u.gdk.target),
634 GDK_GC_XGC(ctx->u.gdk.gc), x, y, string+start, length);
638 #ifdef DRAW_TEXT_CAIRO
639 static void x11font_cairo_setup(unifont_drawctx *ctx, x11font_individual *xfi)
641 if (xfi->pixmap == None) {
642 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
644 GdkWindow *widgetwin = gtk_widget_get_window(ctx->u.cairo.widget);
645 int widgetscr = GDK_SCREEN_XNUMBER(gdk_window_get_screen(widgetwin));
648 xfi->xfs->max_bounds.rbearing - xfi->xfs->min_bounds.lbearing;
650 xfi->xfs->max_bounds.ascent + xfi->xfs->max_bounds.descent;
651 xfi->pixoriginx = -xfi->xfs->min_bounds.lbearing;
652 xfi->pixoriginy = xfi->xfs->max_bounds.ascent;
654 xfi->rowsize = cairo_format_stride_for_width(CAIRO_FORMAT_A1,
656 xfi->allsize = xfi->rowsize * xfi->pixheight;
660 * Test host endianness and use it to set xfi->indexflip,
661 * which is XORed into our left-shift counts in order to
662 * implement the CAIRO_FORMAT_A1 specification, in which
663 * each bitmap byte is oriented LSB-first on little-endian
664 * platforms and MSB-first on big-endian ones.
666 * This is the same technique Cairo itself uses to test
667 * endianness, so hopefully it'll work in any situation
668 * where Cairo is usable at all.
670 static const int endianness_test = 1;
671 xfi->indexflip = (*((char *) &endianness_test) == 1) ? 0 : 7;
674 xfi->pixmap = XCreatePixmap
676 GDK_DRAWABLE_XID(gtk_widget_get_window(ctx->u.cairo.widget)),
677 xfi->pixwidth, xfi->pixheight, 1);
678 gcvals.foreground = WhitePixel(disp, widgetscr);
679 gcvals.background = BlackPixel(disp, widgetscr);
680 gcvals.font = xfi->xfs->fid;
681 xfi->gc = XCreateGC(disp, xfi->pixmap,
682 GCForeground | GCBackground | GCFont, &gcvals);
686 static void x11font_cairo_cache_glyph(x11font_individual *xfi, int glyphindex)
690 unsigned char *bitmap;
691 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
692 const XCharStruct *xcs = x11_char_struct(xfi->xfs, glyphindex >> 8,
695 bitmap = snewn(xfi->allsize, unsigned char);
696 memset(bitmap, 0, xfi->allsize);
698 image = XGetImage(disp, xfi->pixmap, 0, 0,
699 xfi->pixwidth, xfi->pixheight, AllPlanes, XYPixmap);
700 for (y = xfi->pixoriginy - xcs->ascent;
701 y < xfi->pixoriginy + xcs->descent; y++) {
702 for (x = xfi->pixoriginx + xcs->lbearing;
703 x < xfi->pixoriginx + xcs->rbearing; x++) {
704 unsigned long pixel = XGetPixel(image, x, y);
706 int byteindex = y * xfi->rowsize + x/8;
707 int bitindex = (x & 7) ^ xfi->indexflip;
708 bitmap[byteindex] |= 1U << bitindex;
712 XDestroyImage(image);
714 if (xfi->nglyphs <= glyphindex) {
715 /* Round up to the next multiple of 256 on the general
716 * principle that Unicode characters come in contiguous blocks
717 * often used together */
718 int old_nglyphs = xfi->nglyphs;
719 xfi->nglyphs = (glyphindex + 0x100) & ~0xFF;
720 xfi->glyphcache = sresize(xfi->glyphcache, xfi->nglyphs,
721 struct cairo_cached_glyph);
723 while (old_nglyphs < xfi->nglyphs) {
724 xfi->glyphcache[old_nglyphs].surface = NULL;
725 xfi->glyphcache[old_nglyphs].bitmap = NULL;
729 xfi->glyphcache[glyphindex].bitmap = bitmap;
730 xfi->glyphcache[glyphindex].surface = cairo_image_surface_create_for_data
731 (bitmap, CAIRO_FORMAT_A1, xfi->pixwidth, xfi->pixheight, xfi->rowsize);
734 static void x11font_cairo_draw_glyph(unifont_drawctx *ctx,
735 x11font_individual *xfi, int x, int y,
738 if (xfi->glyphcache[glyphindex].surface) {
739 cairo_mask_surface(ctx->u.cairo.cr,
740 xfi->glyphcache[glyphindex].surface,
741 x - xfi->pixoriginx, y - xfi->pixoriginy);
745 static void x11font_cairo_draw_16(unifont_drawctx *ctx,
746 x11font_individual *xfi, int x, int y,
747 const void *vstring, int start, int length)
749 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
750 const XChar2b *string = (const XChar2b *)vstring + start;
752 for (i = 0; i < length; i++) {
753 if (x11_font_has_glyph(xfi->xfs, string[i].byte1, string[i].byte2)) {
754 int glyphindex = (256 * (unsigned char)string[i].byte1 +
755 (unsigned char)string[i].byte2);
756 if (glyphindex >= xfi->nglyphs ||
757 !xfi->glyphcache[glyphindex].surface) {
758 XDrawImageString16(disp, xfi->pixmap, xfi->gc,
759 xfi->pixoriginx, xfi->pixoriginy,
761 x11font_cairo_cache_glyph(xfi, glyphindex);
763 x11font_cairo_draw_glyph(ctx, xfi, x, y, glyphindex);
764 x += XTextWidth16(xfi->xfs, string+i, 1);
769 static void x11font_cairo_draw_8(unifont_drawctx *ctx,
770 x11font_individual *xfi, int x, int y,
771 const void *vstring, int start, int length)
773 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
774 const char *string = (const char *)vstring + start;
776 for (i = 0; i < length; i++) {
777 if (x11_font_has_glyph(xfi->xfs, 0, string[i])) {
778 int glyphindex = (unsigned char)string[i];
779 if (glyphindex >= xfi->nglyphs ||
780 !xfi->glyphcache[glyphindex].surface) {
781 XDrawImageString(disp, xfi->pixmap, xfi->gc,
782 xfi->pixoriginx, xfi->pixoriginy,
784 x11font_cairo_cache_glyph(xfi, glyphindex);
786 x11font_cairo_draw_glyph(ctx, xfi, x, y, glyphindex);
787 x += XTextWidth(xfi->xfs, string+i, 1);
791 #endif /* DRAW_TEXT_CAIRO */
793 struct x11font_drawfuncs {
794 int (*width)(unifont_drawctx *ctx, x11font_individual *xfi,
795 const void *vstring, int start, int length);
796 void (*setup)(unifont_drawctx *ctx, x11font_individual *xfi);
797 void (*draw)(unifont_drawctx *ctx, x11font_individual *xfi, int x, int y,
798 const void *vstring, int start, int length);
802 * This array has two entries per compiled-in drawtype; of each pair,
803 * the first is for an 8-bit font and the second for 16-bit.
805 static const struct x11font_drawfuncs x11font_drawfuncs[2*DRAWTYPE_NTYPES] = {
820 #ifdef DRAW_TEXT_CAIRO
825 x11font_cairo_draw_8,
827 /* [3] cairo, 16-bit */
831 x11font_cairo_draw_16,
836 static void x11font_really_draw_text(const struct x11font_drawfuncs *dfns,
837 unifont_drawctx *ctx,
838 x11font_individual *xfi, int x, int y,
839 const void *string, int nchars,
841 int fontvariable, int cellwidth)
843 int start = 0, step, nsteps, centre;
847 * In a variable-pitch font, we draw one character at a
848 * time, and centre it in the character cell.
855 * In a fixed-pitch font, we can draw the whole lot in one go.
862 dfns->setup(ctx, xfi);
864 while (nsteps-- > 0) {
867 X += (cellwidth - dfns->width(ctx, xfi, string, start, step)) / 2;
869 dfns->draw(ctx, xfi, X, y, string, start, step);
871 dfns->draw(ctx, xfi, X + shadowoffset, y, string, start, step);
878 static void x11font_draw_text(unifont_drawctx *ctx, unifont *font,
879 int x, int y, const wchar_t *string, int len,
880 int wide, int bold, int cellwidth)
882 struct x11font *xfont = (struct x11font *)font;
884 int shadowoffset = 0;
885 int mult = (wide ? 2 : 1);
886 int index = 2 * (int)ctx->type;
892 * Decide which subfont we're using, and whether we have to
895 if (xfont->shadowalways && bold) {
896 shadowoffset = xfont->shadowoffset;
899 sfid = 2 * wide + bold;
900 if (!xfont->fonts[sfid].allocated)
901 x11_alloc_subfont(xfont, sfid);
902 if (bold && !xfont->fonts[sfid].xfs) {
904 shadowoffset = xfont->shadowoffset;
905 sfid = 2 * wide + bold;
906 if (!xfont->fonts[sfid].allocated)
907 x11_alloc_subfont(xfont, sfid);
910 if (!xfont->fonts[sfid].xfs)
911 return; /* we've tried our best, but no luck */
913 if (xfont->sixteen_bit) {
915 * This X font has 16-bit character indices, which means
916 * we can directly use our Unicode input string.
921 xcs = snewn(len, XChar2b);
922 for (i = 0; i < len; i++) {
923 xcs[i].byte1 = string[i] >> 8;
924 xcs[i].byte2 = string[i];
927 x11font_really_draw_text(x11font_drawfuncs + index + 1, ctx,
928 &xfont->fonts[sfid], x, y,
929 xcs, len, shadowoffset,
930 xfont->variable, cellwidth * mult);
934 * This X font has 8-bit indices, so we must convert to the
935 * appropriate character set.
937 char *sbstring = snewn(len+1, char);
938 int sblen = wc_to_mb(xfont->real_charset, 0, string, len,
939 sbstring, len+1, ".", NULL, NULL);
940 x11font_really_draw_text(x11font_drawfuncs + index + 0, ctx,
941 &xfont->fonts[sfid], x, y,
942 sbstring, sblen, shadowoffset,
943 xfont->variable, cellwidth * mult);
948 static void x11font_draw_combining(unifont_drawctx *ctx, unifont *font,
949 int x, int y, const wchar_t *string,
950 int len, int wide, int bold, int cellwidth)
953 * For server-side fonts, there's no sophisticated system for
954 * combining characters intelligently, so the best we can do is to
955 * overprint them on each other in the obvious way.
958 for (i = 0; i < len; i++)
959 x11font_draw_text(ctx, font, x, y, string+i, 1, wide, bold, cellwidth);
962 static void x11font_enum_fonts(GtkWidget *widget,
963 fontsel_add_entry callback, void *callback_ctx)
965 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
968 int nnames, i, max, tmpsize;
972 fontnames = XListFonts(disp, "*", max, &nnames);
974 XFreeFontNames(fontnames);
982 for (i = 0; i < nnames; i++) {
983 struct xlfd_decomposed *xlfd = xlfd_decompose(fontnames[i]);
985 char *p, *font, *style, *stylekey, *charset;
986 int weightkey, slantkey, setwidthkey;
990 * Convert a dismembered XLFD into the format we'll be
991 * using in the font selector.
994 thistmpsize = 4 * strlen(fontnames[i]) + 256;
995 if (tmpsize < thistmpsize) {
996 tmpsize = thistmpsize;
997 tmp = sresize(tmp, tmpsize, char);
1002 * Font name is in the form "family (foundry)". (This is
1003 * what the GTK 1.2 X font selector does, and it seems to
1004 * come out looking reasonably sensible.)
1007 p += 1 + sprintf(p, "%s (%s)", xlfd->family_name, xlfd->foundry);
1013 p += 1 + sprintf(p, "%s-%s", xlfd->charset_registry,
1014 xlfd->charset_encoding);
1017 * Style is a mixture of quite a lot of the fields,
1018 * with some strange formatting.
1021 p += sprintf(p, "%s", xlfd->weight_name[0] ? xlfd->weight_name :
1023 if (!g_ascii_strcasecmp(xlfd->slant, "i"))
1024 p += sprintf(p, " italic");
1025 else if (!g_ascii_strcasecmp(xlfd->slant, "o"))
1026 p += sprintf(p, " oblique");
1027 else if (!g_ascii_strcasecmp(xlfd->slant, "ri"))
1028 p += sprintf(p, " reverse italic");
1029 else if (!g_ascii_strcasecmp(xlfd->slant, "ro"))
1030 p += sprintf(p, " reverse oblique");
1031 else if (!g_ascii_strcasecmp(xlfd->slant, "ot"))
1032 p += sprintf(p, " other-slant");
1033 if (xlfd->setwidth_name[0] &&
1034 g_ascii_strcasecmp(xlfd->setwidth_name, "normal"))
1035 p += sprintf(p, " %s", xlfd->setwidth_name);
1036 if (!g_ascii_strcasecmp(xlfd->spacing, "m"))
1037 p += sprintf(p, " [M]");
1038 if (!g_ascii_strcasecmp(xlfd->spacing, "c"))
1039 p += sprintf(p, " [C]");
1040 if (xlfd->add_style_name[0])
1041 p += sprintf(p, " %s", xlfd->add_style_name);
1044 * Style key is the same stuff as above, but with a
1045 * couple of transformations done on it to make it
1046 * sort more sensibly.
1050 if (!g_ascii_strcasecmp(xlfd->weight_name, "medium") ||
1051 !g_ascii_strcasecmp(xlfd->weight_name, "regular") ||
1052 !g_ascii_strcasecmp(xlfd->weight_name, "normal") ||
1053 !g_ascii_strcasecmp(xlfd->weight_name, "book"))
1055 else if (!g_ascii_strncasecmp(xlfd->weight_name, "demi", 4) ||
1056 !g_ascii_strncasecmp(xlfd->weight_name, "semi", 4))
1060 if (!g_ascii_strcasecmp(xlfd->slant, "r"))
1062 else if (!g_ascii_strncasecmp(xlfd->slant, "r", 1))
1066 if (!g_ascii_strcasecmp(xlfd->setwidth_name, "normal"))
1072 p, "%04d%04d%s%04d%04d%s%04d%04d%s%04d%s%04d%s",
1073 weightkey, (int)strlen(xlfd->weight_name), xlfd->weight_name,
1074 slantkey, (int)strlen(xlfd->slant), xlfd->slant,
1076 (int)strlen(xlfd->setwidth_name), xlfd->setwidth_name,
1077 (int)strlen(xlfd->spacing), xlfd->spacing,
1078 (int)strlen(xlfd->add_style_name), xlfd->add_style_name);
1080 assert(p - tmp < thistmpsize);
1083 * Flags: we need to know whether this is a monospaced
1084 * font, which we do by examining the spacing field
1087 flags = FONTFLAG_SERVERSIDE;
1088 if (!strchr("CcMm", xlfd->spacing[0]))
1089 flags |= FONTFLAG_NONMONOSPACED;
1092 * Some fonts have a pixel size of zero, meaning they're
1093 * treated as scalable. For these purposes, we only want
1094 * fonts whose pixel size we actually know, so filter
1097 if (xlfd->pixel_size)
1098 callback(callback_ctx, fontnames[i], font, charset,
1099 style, stylekey, xlfd->pixel_size, flags,
1105 * This isn't an XLFD, so it must be an alias.
1106 * Transmit it with mostly null data.
1108 * It would be nice to work out if it's monospaced
1109 * here, but at the moment I can't see that being
1110 * anything but computationally hideous. Ah well.
1112 callback(callback_ctx, fontnames[i], fontnames[i], NULL,
1113 NULL, NULL, 0, FONTFLAG_SERVERALIAS, &x11font_vtable);
1118 XFreeFontNames(fontnames);
1121 static char *x11font_canonify_fontname(GtkWidget *widget, const char *name,
1122 int *size, int *flags,
1123 int resolve_aliases)
1126 * When given an X11 font name to try to make sense of for a
1127 * font selector, we must attempt to load it (to see if it
1128 * exists), and then canonify it by extracting its FONT
1129 * property, which should give its full XLFD even if what we
1130 * originally had was a wildcard.
1132 * However, we must carefully avoid canonifying font
1133 * _aliases_, unless specifically asked to, because the font
1134 * selector treats them as worthwhile in their own right.
1137 Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1138 Atom fontprop, fontprop2;
1141 xfs = XLoadQueryFont(disp, name);
1144 return NULL; /* didn't make sense to us, sorry */
1146 fontprop = XInternAtom(disp, "FONT", False);
1148 if (XGetFontProperty(xfs, fontprop, &ret)) {
1149 char *newname = XGetAtomName(disp, (Atom)ret);
1151 unsigned long fsize = 12;
1153 fontprop2 = XInternAtom(disp, "PIXEL_SIZE", False);
1154 if (XGetFontProperty(xfs, fontprop2, &fsize) && fsize > 0) {
1156 XFreeFont(disp, xfs);
1158 if (name[0] == '-' || resolve_aliases)
1159 *flags = FONTFLAG_SERVERSIDE;
1161 *flags = FONTFLAG_SERVERALIAS;
1163 return dupstr(name[0] == '-' || resolve_aliases ?
1169 XFreeFont(disp, xfs);
1171 return NULL; /* something went wrong */
1174 static char *x11font_scale_fontname(GtkWidget *widget, const char *name,
1177 return NULL; /* shan't */
1180 #endif /* NOT_X_WINDOWS */
1182 #if GTK_CHECK_VERSION(2,0,0)
1184 /* ----------------------------------------------------------------------
1185 * Pango font implementation (for GTK 2 only).
1188 #if defined PANGO_PRE_1POINT4 && !defined PANGO_PRE_1POINT6
1189 #define PANGO_PRE_1POINT6 /* make life easier for pre-1.4 folk */
1192 static int pangofont_has_glyph(unifont *font, wchar_t glyph);
1193 static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
1194 int x, int y, const wchar_t *string, int len,
1195 int wide, int bold, int cellwidth);
1196 static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font,
1197 int x, int y, const wchar_t *string,
1198 int len, int wide, int bold,
1200 static unifont *pangofont_create(GtkWidget *widget, const char *name,
1202 int shadowoffset, int shadowalways);
1203 static unifont *pangofont_create_fallback(GtkWidget *widget, int height,
1205 int shadowoffset, int shadowalways);
1206 static void pangofont_destroy(unifont *font);
1207 static void pangofont_enum_fonts(GtkWidget *widget, fontsel_add_entry callback,
1208 void *callback_ctx);
1209 static char *pangofont_canonify_fontname(GtkWidget *widget, const char *name,
1210 int *size, int *flags,
1211 int resolve_aliases);
1212 static char *pangofont_scale_fontname(GtkWidget *widget, const char *name,
1220 PangoFontDescription *desc;
1223 * The containing widget.
1227 * Data passed in to unifont_create().
1229 int bold, shadowoffset, shadowalways;
1231 * Cache of character widths, indexed by Unicode code point. In
1232 * pixels; -1 means we haven't asked Pango about this character
1236 unsigned nwidthcache;
1239 static const struct unifont_vtable pangofont_vtable = {
1241 pangofont_create_fallback,
1243 pangofont_has_glyph,
1244 pangofont_draw_text,
1245 pangofont_draw_combining,
1246 pangofont_enum_fonts,
1247 pangofont_canonify_fontname,
1248 pangofont_scale_fontname,
1253 * This function is used to rigorously validate a
1254 * PangoFontDescription. Later versions of Pango have a nasty
1255 * habit of accepting _any_ old string as input to
1256 * pango_font_description_from_string and returning a font
1257 * description which can actually be used to display text, even if
1258 * they have to do it by falling back to their most default font.
1259 * This is doubtless helpful in some situations, but not here,
1260 * because we need to know if a Pango font string actually _makes
1261 * sense_ in order to fall back to treating it as an X font name
1262 * if it doesn't. So we check that the font family is actually one
1263 * supported by Pango.
1265 static int pangofont_check_desc_makes_sense(PangoContext *ctx,
1266 PangoFontDescription *desc)
1268 #ifndef PANGO_PRE_1POINT6
1271 PangoFontFamily **families;
1272 int i, nfamilies, matched;
1275 * Ask Pango for a list of font families, and iterate through
1276 * them to see if one of them matches the family in the
1277 * PangoFontDescription.
1279 #ifndef PANGO_PRE_1POINT6
1280 map = pango_context_get_font_map(ctx);
1283 pango_font_map_list_families(map, &families, &nfamilies);
1285 pango_context_list_families(ctx, &families, &nfamilies);
1289 for (i = 0; i < nfamilies; i++) {
1290 if (!g_ascii_strcasecmp(pango_font_family_get_name(families[i]),
1291 pango_font_description_get_family(desc))) {
1301 static unifont *pangofont_create_internal(GtkWidget *widget,
1303 PangoFontDescription *desc,
1305 int shadowoffset, int shadowalways)
1307 struct pangofont *pfont;
1308 #ifndef PANGO_PRE_1POINT6
1312 PangoFontMetrics *metrics;
1314 #ifndef PANGO_PRE_1POINT6
1315 map = pango_context_get_font_map(ctx);
1317 pango_font_description_free(desc);
1320 fset = pango_font_map_load_fontset(map, ctx, desc,
1321 pango_context_get_language(ctx));
1323 fset = pango_context_load_fontset(ctx, desc,
1324 pango_context_get_language(ctx));
1327 pango_font_description_free(desc);
1330 metrics = pango_fontset_get_metrics(fset);
1332 pango_font_metrics_get_approximate_digit_width(metrics) == 0) {
1333 pango_font_description_free(desc);
1334 g_object_unref(fset);
1338 pfont = snew(struct pangofont);
1339 pfont->u.vt = &pangofont_vtable;
1341 PANGO_PIXELS(pango_font_metrics_get_approximate_digit_width(metrics));
1342 pfont->u.ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics));
1343 pfont->u.descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
1344 pfont->u.height = pfont->u.ascent + pfont->u.descent;
1345 pfont->u.want_fallback = FALSE;
1346 #ifdef DRAW_TEXT_CAIRO
1347 pfont->u.preferred_drawtype = DRAWTYPE_CAIRO;
1348 #elif defined DRAW_TEXT_GDK
1349 pfont->u.preferred_drawtype = DRAWTYPE_GDK;
1351 #error No drawtype available at all
1353 /* The Pango API is hardwired to UTF-8 */
1354 pfont->u.public_charset = CS_UTF8;
1357 pfont->widget = widget;
1359 pfont->shadowoffset = shadowoffset;
1360 pfont->shadowalways = shadowalways;
1361 pfont->widthcache = NULL;
1362 pfont->nwidthcache = 0;
1364 pango_font_metrics_unref(metrics);
1366 return (unifont *)pfont;
1369 static unifont *pangofont_create(GtkWidget *widget, const char *name,
1371 int shadowoffset, int shadowalways)
1374 PangoFontDescription *desc;
1376 desc = pango_font_description_from_string(name);
1379 ctx = gtk_widget_get_pango_context(widget);
1381 pango_font_description_free(desc);
1384 if (!pangofont_check_desc_makes_sense(ctx, desc)) {
1385 pango_font_description_free(desc);
1388 return pangofont_create_internal(widget, ctx, desc, wide, bold,
1389 shadowoffset, shadowalways);
1392 static unifont *pangofont_create_fallback(GtkWidget *widget, int height,
1394 int shadowoffset, int shadowalways)
1397 PangoFontDescription *desc;
1399 desc = pango_font_description_from_string("Monospace");
1402 ctx = gtk_widget_get_pango_context(widget);
1404 pango_font_description_free(desc);
1407 pango_font_description_set_absolute_size(desc, height * PANGO_SCALE);
1408 return pangofont_create_internal(widget, ctx, desc, wide, bold,
1409 shadowoffset, shadowalways);
1412 static void pangofont_destroy(unifont *font)
1414 struct pangofont *pfont = (struct pangofont *)font;
1415 pango_font_description_free(pfont->desc);
1416 sfree(pfont->widthcache);
1417 g_object_unref(pfont->fset);
1421 static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont,
1422 wchar_t uchr, const char *utfchr, int utflen)
1425 * Here we check whether a character has the same width as the
1426 * character cell it'll be drawn in. Because profiling showed that
1427 * asking Pango for text sizes was a huge bottleneck when we were
1428 * calling it every time we needed to know this, we instead call
1429 * it only on characters we don't already know about, and cache
1433 if ((unsigned)uchr >= pfont->nwidthcache) {
1434 unsigned newsize = ((int)uchr + 0x100) & ~0xFF;
1435 pfont->widthcache = sresize(pfont->widthcache, newsize, int);
1436 while (pfont->nwidthcache < newsize)
1437 pfont->widthcache[pfont->nwidthcache++] = -1;
1440 if (pfont->widthcache[uchr] < 0) {
1441 PangoRectangle rect;
1442 pango_layout_set_text(layout, utfchr, utflen);
1443 pango_layout_get_extents(layout, NULL, &rect);
1444 pfont->widthcache[uchr] = rect.width;
1447 return pfont->widthcache[uchr];
1450 static int pangofont_has_glyph(unifont *font, wchar_t glyph)
1452 /* Pango implements font fallback, so assume it has everything */
1456 #ifdef DRAW_TEXT_GDK
1457 static void pango_gdk_draw_layout(unifont_drawctx *ctx,
1458 gint x, gint y, PangoLayout *layout)
1460 gdk_draw_layout(ctx->u.gdk.target, ctx->u.gdk.gc, x, y, layout);
1464 #ifdef DRAW_TEXT_CAIRO
1465 static void pango_cairo_draw_layout(unifont_drawctx *ctx,
1466 gint x, gint y, PangoLayout *layout)
1468 cairo_move_to(ctx->u.cairo.cr, x, y);
1469 pango_cairo_show_layout(ctx->u.cairo.cr, layout);
1473 static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font,
1474 int x, int y, const wchar_t *string,
1475 int len, int wide, int bold, int cellwidth,
1478 struct pangofont *pfont = (struct pangofont *)font;
1479 PangoLayout *layout;
1480 PangoRectangle rect;
1481 char *utfstring, *utfptr;
1483 int shadowbold = FALSE;
1484 void (*draw_layout)(unifont_drawctx *ctx,
1485 gint x, gint y, PangoLayout *layout) = NULL;
1487 #ifdef DRAW_TEXT_GDK
1488 if (ctx->type == DRAWTYPE_GDK) {
1489 draw_layout = pango_gdk_draw_layout;
1492 #ifdef DRAW_TEXT_CAIRO
1493 if (ctx->type == DRAWTYPE_CAIRO) {
1494 draw_layout = pango_cairo_draw_layout;
1501 y -= pfont->u.ascent;
1503 layout = pango_layout_new(gtk_widget_get_pango_context(pfont->widget));
1504 pango_layout_set_font_description(layout, pfont->desc);
1505 if (bold > pfont->bold) {
1506 if (pfont->shadowalways)
1509 PangoFontDescription *desc2 =
1510 pango_font_description_copy_static(pfont->desc);
1511 pango_font_description_set_weight(desc2, PANGO_WEIGHT_BOLD);
1512 pango_layout_set_font_description(layout, desc2);
1517 * Pango always expects UTF-8, so convert the input wide character
1520 utfstring = snewn(len*6+1, char); /* UTF-8 has max 6 bytes/char */
1521 utflen = wc_to_mb(CS_UTF8, 0, string, len,
1522 utfstring, len*6+1, ".", NULL, NULL);
1525 while (utflen > 0) {
1527 int desired = cellwidth * PANGO_SCALE;
1530 * We want to display every character from this string in
1531 * the centre of its own character cell. In the worst case,
1532 * this requires a separate text-drawing call for each
1533 * character; but in the common case where the font is
1534 * properly fixed-width, we can draw many characters in one
1535 * go which is much faster.
1537 * This still isn't really ideal. If you look at what
1538 * happens in the X protocol as a result of all of this, you
1539 * find - naturally enough - that each call to
1540 * gdk_draw_layout() generates a separate set of X RENDER
1541 * operations involving creating a picture, setting a clip
1542 * rectangle, doing some drawing and undoing the whole lot.
1543 * In an ideal world, we should _always_ be able to turn the
1544 * contents of this loop into a single RenderCompositeGlyphs
1545 * operation which internally specifies inter-character
1546 * deltas to get the spacing right, which would give us full
1547 * speed _even_ in the worst case of a non-fixed-width font.
1548 * However, Pango's architecture and documentation are so
1549 * unhelpful that I have no idea how if at all to persuade
1555 * For a character with combining stuff, we just dump the
1556 * whole lot in one go, and expect it to take up just one
1563 * Start by extracting a single UTF-8 character from the
1567 while (clen < utflen &&
1568 (unsigned char)utfptr[clen] >= 0x80 &&
1569 (unsigned char)utfptr[clen] < 0xC0)
1573 if (is_rtl(string[0]) ||
1574 pangofont_char_width(layout, pfont, string[n-1],
1575 utfptr, clen) != desired) {
1577 * If this character is a right-to-left one, or has an
1578 * unusual width, then we must display it on its own.
1582 * Try to amalgamate a contiguous string of characters
1583 * with the expected sensible width, for the common case
1584 * in which we're using a monospaced font and everything
1585 * works as expected.
1587 while (clen < utflen) {
1589 clen++; /* skip UTF-8 introducer byte */
1590 while (clen < utflen &&
1591 (unsigned char)utfptr[clen] >= 0x80 &&
1592 (unsigned char)utfptr[clen] < 0xC0)
1595 if (is_rtl(string[n-1]) ||
1596 pangofont_char_width(layout, pfont,
1597 string[n-1], utfptr + oldclen,
1598 clen - oldclen) != desired) {
1607 pango_layout_set_text(layout, utfptr, clen);
1608 pango_layout_get_pixel_extents(layout, NULL, &rect);
1611 x + (n*cellwidth - rect.width)/2,
1612 y + (pfont->u.height - rect.height)/2, layout);
1615 x + (n*cellwidth - rect.width)/2 + pfont->shadowoffset,
1616 y + (pfont->u.height - rect.height)/2, layout);
1626 g_object_unref(layout);
1629 static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
1630 int x, int y, const wchar_t *string, int len,
1631 int wide, int bold, int cellwidth)
1633 pangofont_draw_internal(ctx, font, x, y, string, len, wide, bold,
1637 static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font,
1638 int x, int y, const wchar_t *string,
1639 int len, int wide, int bold,
1642 wchar_t *tmpstring = NULL;
1643 if (mk_wcwidth(string[0]) == 0) {
1645 * If we've been told to draw a sequence of _only_ combining
1646 * characters, prefix a space so that they have something to
1649 tmpstring = snewn(len+1, wchar_t);
1650 memcpy(tmpstring+1, string, len * sizeof(wchar_t));
1651 tmpstring[0] = L' ';
1655 pangofont_draw_internal(ctx, font, x, y, string, len, wide, bold,
1661 * Dummy size value to be used when converting a
1662 * PangoFontDescription of a scalable font to a string for
1665 #define PANGO_DUMMY_SIZE 12
1667 static void pangofont_enum_fonts(GtkWidget *widget, fontsel_add_entry callback,
1671 #ifndef PANGO_PRE_1POINT6
1674 PangoFontFamily **families;
1677 ctx = gtk_widget_get_pango_context(widget);
1682 * Ask Pango for a list of font families, and iterate through
1685 #ifndef PANGO_PRE_1POINT6
1686 map = pango_context_get_font_map(ctx);
1689 pango_font_map_list_families(map, &families, &nfamilies);
1691 pango_context_list_families(ctx, &families, &nfamilies);
1693 for (i = 0; i < nfamilies; i++) {
1694 PangoFontFamily *family = families[i];
1695 const char *familyname;
1697 PangoFontFace **faces;
1701 * Set up our flags for this font family, and get the name
1704 flags = FONTFLAG_CLIENTSIDE;
1705 #ifndef PANGO_PRE_1POINT4
1707 * In very early versions of Pango, we can't tell
1708 * monospaced fonts from non-monospaced.
1710 if (!pango_font_family_is_monospace(family))
1711 flags |= FONTFLAG_NONMONOSPACED;
1713 familyname = pango_font_family_get_name(family);
1716 * Go through the available font faces in this family.
1718 pango_font_family_list_faces(family, &faces, &nfaces);
1719 for (j = 0; j < nfaces; j++) {
1720 PangoFontFace *face = faces[j];
1721 PangoFontDescription *desc;
1722 const char *facename;
1724 int k, nsizes, dummysize;
1727 * Get the face name string.
1729 facename = pango_font_face_get_face_name(face);
1732 * Set up a font description with what we've got so
1733 * far. We'll fill in the size field manually and then
1734 * call pango_font_description_to_string() to give the
1735 * full real name of the specific font.
1737 desc = pango_font_face_describe(face);
1740 * See if this font has a list of specific sizes.
1742 #ifndef PANGO_PRE_1POINT4
1743 pango_font_face_list_sizes(face, &sizes, &nsizes);
1746 * In early versions of Pango, that call wasn't
1747 * supported; we just have to assume everything is
1754 * Write a single entry with a dummy size.
1756 dummysize = PANGO_DUMMY_SIZE * PANGO_SCALE;
1762 * If so, go through them one by one.
1764 for (k = 0; k < nsizes; k++) {
1768 pango_font_description_set_size(desc, sizes[k]);
1770 fullname = pango_font_description_to_string(desc);
1773 * Construct the sorting key for font styles.
1779 n = pango_font_description_get_weight(desc);
1780 /* Weight: normal, then lighter, then bolder */
1781 if (n <= PANGO_WEIGHT_NORMAL)
1782 n = PANGO_WEIGHT_NORMAL - n;
1783 p += sprintf(p, "%4d", n);
1785 n = pango_font_description_get_style(desc);
1786 p += sprintf(p, " %2d", n);
1788 n = pango_font_description_get_stretch(desc);
1789 /* Stretch: closer to normal sorts earlier */
1790 n = 2 * abs(PANGO_STRETCH_NORMAL - n) +
1791 (n < PANGO_STRETCH_NORMAL);
1792 p += sprintf(p, " %2d", n);
1794 n = pango_font_description_get_variant(desc);
1795 p += sprintf(p, " %2d", n);
1800 * Got everything. Hand off to the callback.
1801 * (The charset string is NULL, because only
1802 * server-side X fonts use it.)
1804 callback(callback_ctx, fullname, familyname, NULL, facename,
1806 (sizes == &dummysize ? 0 : PANGO_PIXELS(sizes[k])),
1807 flags, &pangofont_vtable);
1811 if (sizes != &dummysize)
1814 pango_font_description_free(desc);
1821 static char *pangofont_canonify_fontname(GtkWidget *widget, const char *name,
1822 int *size, int *flags,
1823 int resolve_aliases)
1826 * When given a Pango font name to try to make sense of for a
1827 * font selector, we must normalise it to PANGO_DUMMY_SIZE and
1828 * extract its original size (in pixels) into the `size' field.
1831 #ifndef PANGO_PRE_1POINT6
1834 PangoFontDescription *desc;
1836 PangoFontMetrics *metrics;
1837 char *newname, *retname;
1839 desc = pango_font_description_from_string(name);
1842 ctx = gtk_widget_get_pango_context(widget);
1844 pango_font_description_free(desc);
1847 if (!pangofont_check_desc_makes_sense(ctx, desc)) {
1848 pango_font_description_free(desc);
1851 #ifndef PANGO_PRE_1POINT6
1852 map = pango_context_get_font_map(ctx);
1854 pango_font_description_free(desc);
1857 fset = pango_font_map_load_fontset(map, ctx, desc,
1858 pango_context_get_language(ctx));
1860 fset = pango_context_load_fontset(ctx, desc,
1861 pango_context_get_language(ctx));
1864 pango_font_description_free(desc);
1867 metrics = pango_fontset_get_metrics(fset);
1869 pango_font_metrics_get_approximate_digit_width(metrics) == 0) {
1870 pango_font_description_free(desc);
1871 g_object_unref(fset);
1875 *size = PANGO_PIXELS(pango_font_description_get_size(desc));
1876 *flags = FONTFLAG_CLIENTSIDE;
1877 pango_font_description_set_size(desc, PANGO_DUMMY_SIZE * PANGO_SCALE);
1878 newname = pango_font_description_to_string(desc);
1879 retname = dupstr(newname);
1882 pango_font_metrics_unref(metrics);
1883 pango_font_description_free(desc);
1884 g_object_unref(fset);
1889 static char *pangofont_scale_fontname(GtkWidget *widget, const char *name,
1892 PangoFontDescription *desc;
1893 char *newname, *retname;
1895 desc = pango_font_description_from_string(name);
1898 pango_font_description_set_size(desc, size * PANGO_SCALE);
1899 newname = pango_font_description_to_string(desc);
1900 retname = dupstr(newname);
1902 pango_font_description_free(desc);
1907 #endif /* GTK_CHECK_VERSION(2,0,0) */
1909 /* ----------------------------------------------------------------------
1910 * Outermost functions which do the vtable dispatch.
1914 * Complete list of font-type subclasses. Listed in preference
1915 * order for unifont_create(). (That is, in the extremely unlikely
1916 * event that the same font name is valid as both a Pango and an
1917 * X11 font, it will be interpreted as the former in the absence
1918 * of an explicit type-disambiguating prefix.)
1920 * The 'multifont' subclass is omitted here, as discussed above.
1922 static const struct unifont_vtable *unifont_types[] = {
1923 #if GTK_CHECK_VERSION(2,0,0)
1926 #ifndef NOT_X_WINDOWS
1932 * Function which takes a font name and processes the optional
1933 * scheme prefix. Returns the tail of the font name suitable for
1934 * passing to individual font scheme functions, and also provides
1935 * a subrange of the unifont_types[] array above.
1937 * The return values `start' and `end' denote a half-open interval
1938 * in unifont_types[]; that is, the correct way to iterate over
1941 * for (i = start; i < end; i++) {...}
1943 static const char *unifont_do_prefix(const char *name, int *start, int *end)
1945 int colonpos = strcspn(name, ":");
1948 if (name[colonpos]) {
1950 * There's a colon prefix on the font name. Use it to work
1951 * out which subclass to use.
1953 for (i = 0; i < lenof(unifont_types); i++) {
1954 if (strlen(unifont_types[i]->prefix) == colonpos &&
1955 !strncmp(unifont_types[i]->prefix, name, colonpos)) {
1958 return name + colonpos + 1;
1962 * None matched, so return an empty scheme list to prevent
1963 * any scheme from being called at all.
1966 return name + colonpos + 1;
1969 * No colon prefix, so just use all the subclasses.
1972 *end = lenof(unifont_types);
1977 unifont *unifont_create(GtkWidget *widget, const char *name, int wide,
1978 int bold, int shadowoffset, int shadowalways)
1982 name = unifont_do_prefix(name, &start, &end);
1984 for (i = start; i < end; i++) {
1985 unifont *ret = unifont_types[i]->create(widget, name, wide, bold,
1986 shadowoffset, shadowalways);
1990 return NULL; /* font not found in any scheme */
1993 void unifont_destroy(unifont *font)
1995 font->vt->destroy(font);
1998 void unifont_draw_text(unifont_drawctx *ctx, unifont *font,
1999 int x, int y, const wchar_t *string, int len,
2000 int wide, int bold, int cellwidth)
2002 font->vt->draw_text(ctx, font, x, y, string, len, wide, bold, cellwidth);
2005 void unifont_draw_combining(unifont_drawctx *ctx, unifont *font,
2006 int x, int y, const wchar_t *string, int len,
2007 int wide, int bold, int cellwidth)
2009 font->vt->draw_combining(ctx, font, x, y, string, len, wide, bold,
2013 /* ----------------------------------------------------------------------
2014 * Multiple-font wrapper. This is a type of unifont which encapsulates
2015 * up to two other unifonts, permitting missing glyphs in the main
2016 * font to be filled in by a fallback font.
2018 * This is a type of unifont just like the previous two, but it has a
2019 * separate constructor which is manually called by the client, so it
2020 * doesn't appear in the list of available font types enumerated by
2021 * unifont_create. This means it's not used by unifontsel either, so
2022 * it doesn't need to support any methods except draw_text and
2026 static void multifont_draw_text(unifont_drawctx *ctx, unifont *font,
2027 int x, int y, const wchar_t *string, int len,
2028 int wide, int bold, int cellwidth);
2029 static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font,
2030 int x, int y, const wchar_t *string,
2031 int len, int wide, int bold,
2033 static void multifont_destroy(unifont *font);
2041 static const struct unifont_vtable multifont_vtable = {
2042 NULL, /* creation is done specially */
2046 multifont_draw_text,
2047 multifont_draw_combining,
2054 unifont *multifont_create(GtkWidget *widget, const char *name,
2056 int shadowoffset, int shadowalways)
2059 unifont *font, *fallback;
2060 struct multifont *mfont;
2062 font = unifont_create(widget, name, wide, bold,
2063 shadowoffset, shadowalways);
2068 if (font->want_fallback) {
2069 for (i = 0; i < lenof(unifont_types); i++) {
2070 if (unifont_types[i]->create_fallback) {
2071 fallback = unifont_types[i]->create_fallback
2072 (widget, font->height, wide, bold,
2073 shadowoffset, shadowalways);
2081 * Construct our multifont. Public members are all copied from the
2082 * primary font we're wrapping.
2084 mfont = snew(struct multifont);
2085 mfont->u.vt = &multifont_vtable;
2086 mfont->u.width = font->width;
2087 mfont->u.ascent = font->ascent;
2088 mfont->u.descent = font->descent;
2089 mfont->u.height = font->height;
2090 mfont->u.public_charset = font->public_charset;
2091 mfont->u.want_fallback = FALSE; /* shouldn't be needed, but just in case */
2092 mfont->u.preferred_drawtype = font->preferred_drawtype;
2094 mfont->fallback = fallback;
2096 return (unifont *)mfont;
2099 static void multifont_destroy(unifont *font)
2101 struct multifont *mfont = (struct multifont *)font;
2102 unifont_destroy(mfont->main);
2103 if (mfont->fallback)
2104 unifont_destroy(mfont->fallback);
2108 typedef void (*unifont_draw_func_t)(unifont_drawctx *ctx, unifont *font,
2109 int x, int y, const wchar_t *string,
2110 int len, int wide, int bold,
2113 static void multifont_draw_main(unifont_drawctx *ctx, unifont *font, int x,
2114 int y, const wchar_t *string, int len,
2115 int wide, int bold, int cellwidth,
2116 int cellinc, unifont_draw_func_t draw)
2118 struct multifont *mfont = (struct multifont *)font;
2124 * Find a maximal sequence of characters which are, or are
2125 * not, supported by our main font.
2127 ok = mfont->main->vt->has_glyph(mfont->main, string[0]);
2130 !mfont->main->vt->has_glyph(mfont->main, string[i]) == !ok;
2136 f = ok ? mfont->main : mfont->fallback;
2138 draw(ctx, f, x, y, string, i, wide, bold, cellwidth);
2145 static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x,
2146 int y, const wchar_t *string, int len,
2147 int wide, int bold, int cellwidth)
2149 multifont_draw_main(ctx, font, x, y, string, len, wide, bold,
2150 cellwidth, cellwidth, unifont_draw_text);
2153 static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font,
2154 int x, int y, const wchar_t *string,
2155 int len, int wide, int bold,
2158 multifont_draw_main(ctx, font, x, y, string, len, wide, bold,
2159 cellwidth, 0, unifont_draw_combining);
2162 #if GTK_CHECK_VERSION(2,0,0)
2164 /* ----------------------------------------------------------------------
2165 * Implementation of a unified font selector. Used on GTK 2 only;
2166 * for GTK 1 we still use the standard font selector.
2169 typedef struct fontinfo fontinfo;
2171 typedef struct unifontsel_internal {
2172 /* This must be the structure's first element, for cross-casting */
2174 GtkListStore *family_model, *style_model, *size_model;
2175 GtkWidget *family_list, *style_list, *size_entry, *size_list;
2176 GtkWidget *filter_buttons[4];
2177 int n_filter_buttons;
2178 GtkWidget *preview_area;
2179 #ifndef NO_BACKING_PIXMAPS
2180 GdkPixmap *preview_pixmap;
2182 int preview_width, preview_height;
2183 GdkColor preview_fg, preview_bg;
2185 tree234 *fonts_by_realname, *fonts_by_selorder;
2187 int selsize, intendedsize;
2188 int inhibit_response; /* inhibit callbacks when we change GUI controls */
2189 } unifontsel_internal;
2192 * The structure held in the tree234s. All the string members are
2193 * part of the same allocated area, so don't need freeing
2198 char *family, *charset, *style, *stylekey;
2201 * Fallback sorting key, to permit multiple identical entries
2202 * to exist in the selorder tree.
2206 * Indices mapping fontinfo structures to indices in the list
2207 * boxes. sizeindex is irrelevant if the font is scalable
2210 int familyindex, styleindex, sizeindex;
2212 * The class of font.
2214 const struct unifont_vtable *fontclass;
2217 struct fontinfo_realname_find {
2218 const char *realname;
2222 static int strnullcasecmp(const char *a, const char *b)
2227 * If exactly one of the inputs is NULL, it compares before
2230 if ((i = (!b) - (!a)) != 0)
2234 * NULL compares equal.
2240 * Otherwise, ordinary strcasecmp.
2242 return g_ascii_strcasecmp(a, b);
2245 static int fontinfo_realname_compare(void *av, void *bv)
2247 fontinfo *a = (fontinfo *)av;
2248 fontinfo *b = (fontinfo *)bv;
2251 if ((i = strnullcasecmp(a->realname, b->realname)) != 0)
2253 if ((a->flags & FONTFLAG_SORT_MASK) != (b->flags & FONTFLAG_SORT_MASK))
2254 return ((a->flags & FONTFLAG_SORT_MASK) <
2255 (b->flags & FONTFLAG_SORT_MASK) ? -1 : +1);
2259 static int fontinfo_realname_find(void *av, void *bv)
2261 struct fontinfo_realname_find *a = (struct fontinfo_realname_find *)av;
2262 fontinfo *b = (fontinfo *)bv;
2265 if ((i = strnullcasecmp(a->realname, b->realname)) != 0)
2267 if ((a->flags & FONTFLAG_SORT_MASK) != (b->flags & FONTFLAG_SORT_MASK))
2268 return ((a->flags & FONTFLAG_SORT_MASK) <
2269 (b->flags & FONTFLAG_SORT_MASK) ? -1 : +1);
2273 static int fontinfo_selorder_compare(void *av, void *bv)
2275 fontinfo *a = (fontinfo *)av;
2276 fontinfo *b = (fontinfo *)bv;
2278 if ((i = strnullcasecmp(a->family, b->family)) != 0)
2281 * Font class comes immediately after family, so that fonts
2282 * from different classes with the same family
2284 if ((a->flags & FONTFLAG_SORT_MASK) != (b->flags & FONTFLAG_SORT_MASK))
2285 return ((a->flags & FONTFLAG_SORT_MASK) <
2286 (b->flags & FONTFLAG_SORT_MASK) ? -1 : +1);
2287 if ((i = strnullcasecmp(a->charset, b->charset)) != 0)
2289 if ((i = strnullcasecmp(a->stylekey, b->stylekey)) != 0)
2291 if ((i = strnullcasecmp(a->style, b->style)) != 0)
2293 if (a->size != b->size)
2294 return (a->size < b->size ? -1 : +1);
2295 if (a->index != b->index)
2296 return (a->index < b->index ? -1 : +1);
2300 static void unifontsel_draw_preview_text(unifontsel_internal *fs);
2302 static void unifontsel_deselect(unifontsel_internal *fs)
2304 fs->selected = NULL;
2305 gtk_list_store_clear(fs->style_model);
2306 gtk_list_store_clear(fs->size_model);
2307 gtk_widget_set_sensitive(fs->u.ok_button, FALSE);
2308 gtk_widget_set_sensitive(fs->size_entry, FALSE);
2309 unifontsel_draw_preview_text(fs);
2312 static void unifontsel_setup_familylist(unifontsel_internal *fs)
2315 int i, listindex, minpos = -1, maxpos = -1;
2316 char *currfamily = NULL;
2320 fs->inhibit_response = TRUE;
2322 gtk_list_store_clear(fs->family_model);
2326 * Search through the font tree for anything matching our
2327 * current filter criteria. When we find one, add its font
2328 * name to the list box.
2330 for (i = 0 ;; i++) {
2331 info = (fontinfo *)index234(fs->fonts_by_selorder, i);
2333 * info may be NULL if we've just run off the end of the
2334 * tree. We must still do a processing pass in that
2335 * situation, in case we had an unfinished font record in
2338 if (info && (info->flags &~ fs->filter_flags)) {
2339 info->familyindex = -1;
2340 continue; /* we're filtering out this font */
2342 if (!info || strnullcasecmp(currfamily, info->family) ||
2343 currflags != (info->flags & FONTFLAG_SORT_MASK)) {
2345 * We've either finished a family, or started a new
2349 gtk_list_store_append(fs->family_model, &iter);
2350 gtk_list_store_set(fs->family_model, &iter,
2351 0, currfamily, 1, minpos, 2, maxpos+1, -1);
2356 currfamily = info->family;
2357 currflags = info->flags & FONTFLAG_SORT_MASK;
2361 break; /* now we're done */
2362 info->familyindex = listindex;
2367 * If we've just filtered out the previously selected font,
2368 * deselect it thoroughly.
2370 if (fs->selected && fs->selected->familyindex < 0)
2371 unifontsel_deselect(fs);
2373 fs->inhibit_response = FALSE;
2376 static void unifontsel_setup_stylelist(unifontsel_internal *fs,
2380 int i, listindex, minpos = -1, maxpos = -1, started = FALSE;
2381 char *currcs = NULL, *currstyle = NULL;
2384 gtk_list_store_clear(fs->style_model);
2389 * Search through the font tree for anything matching our
2390 * current filter criteria. When we find one, add its charset
2391 * and/or style name to the list box.
2393 for (i = start; i <= end; i++) {
2397 info = (fontinfo *)index234(fs->fonts_by_selorder, i);
2399 * info may be NULL if we've just run off the end of the
2400 * relevant data. We must still do a processing pass in
2401 * that situation, in case we had an unfinished font
2402 * record in progress.
2404 if (info && (info->flags &~ fs->filter_flags)) {
2405 info->styleindex = -1;
2406 continue; /* we're filtering out this font */
2408 if (!info || !started || strnullcasecmp(currcs, info->charset) ||
2409 strnullcasecmp(currstyle, info->style)) {
2411 * We've either finished a style/charset, or started a
2416 gtk_list_store_append(fs->style_model, &iter);
2417 gtk_list_store_set(fs->style_model, &iter,
2418 0, currstyle, 1, minpos, 2, maxpos+1,
2419 3, TRUE, 4, PANGO_WEIGHT_NORMAL, -1);
2424 if (info->charset && strnullcasecmp(currcs, info->charset)) {
2425 gtk_list_store_append(fs->style_model, &iter);
2426 gtk_list_store_set(fs->style_model, &iter,
2427 0, info->charset, 1, -1, 2, -1,
2428 3, FALSE, 4, PANGO_WEIGHT_BOLD, -1);
2431 currcs = info->charset;
2432 currstyle = info->style;
2436 break; /* now we're done */
2437 info->styleindex = listindex;
2442 static const int unifontsel_default_sizes[] = { 10, 12, 14, 16, 20, 24, 32 };
2444 static void unifontsel_setup_sizelist(unifontsel_internal *fs,
2452 gtk_list_store_clear(fs->size_model);
2456 * Search through the font tree for anything matching our
2457 * current filter criteria. When we find one, add its font
2458 * name to the list box.
2460 for (i = start; i < end; i++) {
2461 info = (fontinfo *)index234(fs->fonts_by_selorder, i);
2462 if (info->flags &~ fs->filter_flags) {
2463 info->sizeindex = -1;
2464 continue; /* we're filtering out this font */
2467 sprintf(sizetext, "%d", info->size);
2468 info->sizeindex = listindex;
2469 gtk_list_store_append(fs->size_model, &iter);
2470 gtk_list_store_set(fs->size_model, &iter,
2471 0, sizetext, 1, i, 2, info->size, -1);
2479 for (j = 0; j < lenof(unifontsel_default_sizes); j++) {
2480 sprintf(sizetext, "%d", unifontsel_default_sizes[j]);
2481 gtk_list_store_append(fs->size_model, &iter);
2482 gtk_list_store_set(fs->size_model, &iter, 0, sizetext, 1, i,
2483 2, unifontsel_default_sizes[j], -1);
2490 static void unifontsel_set_filter_buttons(unifontsel_internal *fs)
2494 for (i = 0; i < fs->n_filter_buttons; i++) {
2495 int flagbit = GPOINTER_TO_INT(g_object_get_data
2496 (G_OBJECT(fs->filter_buttons[i]),
2498 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fs->filter_buttons[i]),
2499 !!(fs->filter_flags & flagbit));
2503 static void unifontsel_draw_preview_text_inner(unifont_drawctx *dctx,
2504 unifontsel_internal *fs)
2507 char *sizename = NULL;
2508 fontinfo *info = fs->selected;
2511 sizename = info->fontclass->scale_fontname
2512 (GTK_WIDGET(fs->u.window), info->realname, fs->selsize);
2513 font = info->fontclass->create(GTK_WIDGET(fs->u.window),
2514 sizename ? sizename : info->realname,
2515 FALSE, FALSE, 0, 0);
2519 #ifdef DRAW_TEXT_GDK
2520 if (dctx->type == DRAWTYPE_GDK) {
2521 gdk_gc_set_foreground(dctx->u.gdk.gc, &fs->preview_bg);
2522 gdk_draw_rectangle(dctx->u.gdk.target, dctx->u.gdk.gc, 1, 0, 0,
2523 fs->preview_width, fs->preview_height);
2524 gdk_gc_set_foreground(dctx->u.gdk.gc, &fs->preview_fg);
2527 #ifdef DRAW_TEXT_CAIRO
2528 if (dctx->type == DRAWTYPE_CAIRO) {
2529 cairo_set_source_rgb(dctx->u.cairo.cr,
2530 fs->preview_bg.red / 65535.0,
2531 fs->preview_bg.green / 65535.0,
2532 fs->preview_bg.blue / 65535.0);
2533 cairo_paint(dctx->u.cairo.cr);
2534 cairo_set_source_rgb(dctx->u.cairo.cr,
2535 fs->preview_fg.red / 65535.0,
2536 fs->preview_fg.green / 65535.0,
2537 fs->preview_fg.blue / 65535.0);
2543 * The pangram used here is rather carefully
2544 * constructed: it contains a sequence of very narrow
2545 * letters (`jil') and a pair of adjacent very wide
2548 * If the user selects a proportional font, it will be
2549 * coerced into fixed-width character cells when used
2550 * in the actual terminal window. We therefore display
2551 * it the same way in the preview pane, so as to show
2552 * it the way it will actually be displayed - and we
2553 * deliberately pick a pangram which will show the
2554 * resulting miskerning at its worst.
2556 * We aren't trying to sell people these fonts; we're
2557 * trying to let them make an informed choice. Better
2558 * that they find out the problems with using
2559 * proportional fonts in terminal windows here than
2560 * that they go to the effort of selecting their font
2561 * and _then_ realise it was a mistake.
2563 info->fontclass->draw_text(dctx, font,
2565 L"bankrupt jilted showmen quiz convex fogey",
2566 41, FALSE, FALSE, font->width);
2567 info->fontclass->draw_text(dctx, font,
2568 0, font->ascent + font->height,
2569 L"BANKRUPT JILTED SHOWMEN QUIZ CONVEX FOGEY",
2570 41, FALSE, FALSE, font->width);
2572 * The ordering of punctuation here is also selected
2573 * with some specific aims in mind. I put ` and '
2574 * together because some software (and people) still
2575 * use them as matched quotes no matter what Unicode
2576 * might say on the matter, so people can quickly
2577 * check whether they look silly in a candidate font.
2578 * The sequence #_@ is there to let people judge the
2579 * suitability of the underscore as an effectively
2580 * alphabetic character (since that's how it's often
2581 * used in practice, at least by programmers).
2583 info->fontclass->draw_text(dctx, font,
2584 0, font->ascent + font->height * 2,
2585 L"0123456789!?,.:;<>()[]{}\\/`'\"+*-=~#_@|%&^$",
2586 42, FALSE, FALSE, font->width);
2588 info->fontclass->destroy(font);
2594 static void unifontsel_draw_preview_text(unifontsel_internal *fs)
2596 unifont_drawctx dctx;
2599 #ifndef NO_BACKING_PIXMAPS
2600 target = fs->preview_pixmap;
2602 target = gtk_widget_get_window(fs->preview_area);
2604 if (!target) /* we may be called when we haven't created everything yet */
2607 dctx.type = DRAWTYPE_DEFAULT;
2608 #ifdef DRAW_TEXT_GDK
2609 if (dctx.type == DRAWTYPE_GDK) {
2610 dctx.u.gdk.target = target;
2611 dctx.u.gdk.gc = gdk_gc_new(target);
2614 #ifdef DRAW_TEXT_CAIRO
2615 if (dctx.type == DRAWTYPE_CAIRO) {
2616 dctx.u.cairo.widget = GTK_WIDGET(fs->preview_area);
2617 dctx.u.cairo.cr = gdk_cairo_create(target);
2621 unifontsel_draw_preview_text_inner(&dctx, fs);
2623 #ifdef DRAW_TEXT_GDK
2624 if (dctx.type == DRAWTYPE_GDK) {
2625 gdk_gc_unref(dctx.u.gdk.gc);
2628 #ifdef DRAW_TEXT_CAIRO
2629 if (dctx.type == DRAWTYPE_CAIRO) {
2630 cairo_destroy(dctx.u.cairo.cr);
2634 gdk_window_invalidate_rect(gtk_widget_get_window(fs->preview_area),
2638 static void unifontsel_select_font(unifontsel_internal *fs,
2639 fontinfo *info, int size, int leftlist,
2640 int size_is_explicit)
2645 GtkTreePath *treepath;
2648 fs->inhibit_response = TRUE;
2650 fs->selected = info;
2652 if (size_is_explicit)
2653 fs->intendedsize = size;
2655 gtk_widget_set_sensitive(fs->u.ok_button, TRUE);
2658 * Find the index of this fontinfo in the selorder list.
2661 findpos234(fs->fonts_by_selorder, info, NULL, &index);
2665 * Adjust the font selector flags and redo the font family
2666 * list box, if necessary.
2668 if (leftlist <= 0 &&
2669 (fs->filter_flags | info->flags) != fs->filter_flags) {
2670 fs->filter_flags |= info->flags;
2671 unifontsel_set_filter_buttons(fs);
2672 unifontsel_setup_familylist(fs);
2676 * Find the appropriate family name and select it in the list.
2678 assert(info->familyindex >= 0);
2679 treepath = gtk_tree_path_new_from_indices(info->familyindex, -1);
2680 gtk_tree_selection_select_path
2681 (gtk_tree_view_get_selection(GTK_TREE_VIEW(fs->family_list)),
2683 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->family_list),
2684 treepath, NULL, FALSE, 0.0, 0.0);
2685 success = gtk_tree_model_get_iter(GTK_TREE_MODEL(fs->family_model),
2688 gtk_tree_path_free(treepath);
2691 * Now set up the font style list.
2693 gtk_tree_model_get(GTK_TREE_MODEL(fs->family_model), &iter,
2694 1, &minval, 2, &maxval, -1);
2696 unifontsel_setup_stylelist(fs, minval, maxval);
2699 * Find the appropriate style name and select it in the list.
2702 assert(info->styleindex >= 0);
2703 treepath = gtk_tree_path_new_from_indices(info->styleindex, -1);
2704 gtk_tree_selection_select_path
2705 (gtk_tree_view_get_selection(GTK_TREE_VIEW(fs->style_list)),
2707 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->style_list),
2708 treepath, NULL, FALSE, 0.0, 0.0);
2709 gtk_tree_model_get_iter(GTK_TREE_MODEL(fs->style_model),
2711 gtk_tree_path_free(treepath);
2714 * And set up the size list.
2716 gtk_tree_model_get(GTK_TREE_MODEL(fs->style_model), &iter,
2717 1, &minval, 2, &maxval, -1);
2719 unifontsel_setup_sizelist(fs, minval, maxval);
2722 * Find the appropriate size, and select it in the list.
2725 assert(info->sizeindex >= 0);
2726 treepath = gtk_tree_path_new_from_indices(info->sizeindex, -1);
2727 gtk_tree_selection_select_path
2728 (gtk_tree_view_get_selection(GTK_TREE_VIEW(fs->size_list)),
2730 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->size_list),
2731 treepath, NULL, FALSE, 0.0, 0.0);
2732 gtk_tree_path_free(treepath);
2736 for (j = 0; j < lenof(unifontsel_default_sizes); j++)
2737 if (unifontsel_default_sizes[j] == size) {
2738 treepath = gtk_tree_path_new_from_indices(j, -1);
2739 gtk_tree_view_set_cursor(GTK_TREE_VIEW(fs->size_list),
2740 treepath, NULL, FALSE);
2741 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fs->size_list),
2742 treepath, NULL, FALSE, 0.0,
2744 gtk_tree_path_free(treepath);
2749 * And set up the font size text entry box.
2753 sprintf(sizetext, "%d", size);
2754 gtk_entry_set_text(GTK_ENTRY(fs->size_entry), sizetext);
2758 unifontsel_setup_sizelist(fs, 0, 0);
2759 gtk_entry_set_text(GTK_ENTRY(fs->size_entry), "");
2763 * Grey out the font size edit box if we're not using a
2766 gtk_editable_set_editable(GTK_EDITABLE(fs->size_entry),
2767 fs->selected->size == 0);
2768 gtk_widget_set_sensitive(fs->size_entry, fs->selected->size == 0);
2770 unifontsel_draw_preview_text(fs);
2772 fs->inhibit_response = FALSE;
2775 static void unifontsel_button_toggled(GtkToggleButton *tb, gpointer data)
2777 unifontsel_internal *fs = (unifontsel_internal *)data;
2778 int newstate = gtk_toggle_button_get_active(tb);
2780 int flagbit = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tb),
2784 newflags = fs->filter_flags | flagbit;
2786 newflags = fs->filter_flags & ~flagbit;
2788 if (fs->filter_flags != newflags) {
2789 fs->filter_flags = newflags;
2790 unifontsel_setup_familylist(fs);
2794 static void unifontsel_add_entry(void *ctx, const char *realfontname,
2795 const char *family, const char *charset,
2796 const char *style, const char *stylekey,
2797 int size, int flags,
2798 const struct unifont_vtable *fontclass)
2800 unifontsel_internal *fs = (unifontsel_internal *)ctx;
2805 totalsize = sizeof(fontinfo) + strlen(realfontname) +
2806 (family ? strlen(family) : 0) + (charset ? strlen(charset) : 0) +
2807 (style ? strlen(style) : 0) + (stylekey ? strlen(stylekey) : 0) + 10;
2808 info = (fontinfo *)smalloc(totalsize);
2809 info->fontclass = fontclass;
2810 p = (char *)info + sizeof(fontinfo);
2812 strcpy(p, realfontname);
2819 info->family = NULL;
2825 info->charset = NULL;
2834 strcpy(p, stylekey);
2837 info->stylekey = NULL;
2838 assert(p - (char *)info <= totalsize);
2840 info->flags = flags;
2841 info->index = count234(fs->fonts_by_selorder);
2844 * It's just conceivable that a misbehaving font enumerator
2845 * might tell us about the same font real name more than once,
2846 * in which case we should silently drop the new one.
2848 if (add234(fs->fonts_by_realname, info) != info) {
2853 * However, we should never get a duplicate key in the
2854 * selorder tree, because the index field carefully
2855 * disambiguates otherwise identical records.
2857 add234(fs->fonts_by_selorder, info);
2860 static fontinfo *update_for_intended_size(unifontsel_internal *fs,
2863 fontinfo info2, *below, *above;
2867 * Copy the info structure. This doesn't copy its dynamic
2868 * string fields, but that's unimportant because all we're
2869 * going to do is to adjust the size field and use it in one
2873 info2.size = fs->intendedsize;
2876 * Search in the tree to find the fontinfo structure which
2877 * best approximates the size the user last requested.
2879 below = findrelpos234(fs->fonts_by_selorder, &info2, NULL,
2883 above = index234(fs->fonts_by_selorder, pos+1);
2886 * See if we've found it exactly, which is an easy special
2887 * case. If we have, it'll be in `below' and not `above',
2888 * because we did a REL234_LE rather than REL234_LT search.
2890 if (below && !fontinfo_selorder_compare(&info2, below))
2894 * Now we've either found two suitable fonts, one smaller and
2895 * one larger, or we're at one or other extreme end of the
2896 * scale. Find out which, by NULLing out either of below and
2897 * above if it differs from this one in any respect but size
2898 * (and the disambiguating index field). Bear in mind, also,
2899 * that either one might _already_ be NULL if we're at the
2900 * extreme ends of the font list.
2903 info2.size = below->size;
2904 info2.index = below->index;
2905 if (fontinfo_selorder_compare(&info2, below))
2909 info2.size = above->size;
2910 info2.index = above->index;
2911 if (fontinfo_selorder_compare(&info2, above))
2916 * Now return whichever of above and below is non-NULL, if
2917 * that's unambiguous.
2925 * And now we really do have to make a choice about whether to
2926 * round up or down. We'll do it by rounding to nearest,
2927 * breaking ties by rounding up.
2929 if (above->size - fs->intendedsize <= fs->intendedsize - below->size)
2935 static void family_changed(GtkTreeSelection *treeselection, gpointer data)
2937 unifontsel_internal *fs = (unifontsel_internal *)data;
2938 GtkTreeModel *treemodel;
2939 GtkTreeIter treeiter;
2943 if (fs->inhibit_response) /* we made this change ourselves */
2946 if (!gtk_tree_selection_get_selected(treeselection, &treemodel, &treeiter))
2949 gtk_tree_model_get(treemodel, &treeiter, 1, &minval, -1);
2950 info = (fontinfo *)index234(fs->fonts_by_selorder, minval);
2951 info = update_for_intended_size(fs, info);
2953 return; /* _shouldn't_ happen unless font list is completely funted */
2955 fs->selsize = fs->intendedsize; /* font is scalable */
2956 unifontsel_select_font(fs, info, info->size ? info->size : fs->selsize,
2960 static void style_changed(GtkTreeSelection *treeselection, gpointer data)
2962 unifontsel_internal *fs = (unifontsel_internal *)data;
2963 GtkTreeModel *treemodel;
2964 GtkTreeIter treeiter;
2968 if (fs->inhibit_response) /* we made this change ourselves */
2971 if (!gtk_tree_selection_get_selected(treeselection, &treemodel, &treeiter))
2974 gtk_tree_model_get(treemodel, &treeiter, 1, &minval, -1);
2976 return; /* somehow a charset heading got clicked */
2977 info = (fontinfo *)index234(fs->fonts_by_selorder, minval);
2978 info = update_for_intended_size(fs, info);
2980 return; /* _shouldn't_ happen unless font list is completely funted */
2982 fs->selsize = fs->intendedsize; /* font is scalable */
2983 unifontsel_select_font(fs, info, info->size ? info->size : fs->selsize,
2987 static void size_changed(GtkTreeSelection *treeselection, gpointer data)
2989 unifontsel_internal *fs = (unifontsel_internal *)data;
2990 GtkTreeModel *treemodel;
2991 GtkTreeIter treeiter;
2995 if (fs->inhibit_response) /* we made this change ourselves */
2998 if (!gtk_tree_selection_get_selected(treeselection, &treemodel, &treeiter))
3001 gtk_tree_model_get(treemodel, &treeiter, 1, &minval, 2, &size, -1);
3002 info = (fontinfo *)index234(fs->fonts_by_selorder, minval);
3003 unifontsel_select_font(fs, info, info->size ? info->size : size, 3, TRUE);
3006 static void size_entry_changed(GtkEditable *ed, gpointer data)
3008 unifontsel_internal *fs = (unifontsel_internal *)data;
3012 if (fs->inhibit_response) /* we made this change ourselves */
3015 text = gtk_entry_get_text(GTK_ENTRY(ed));
3019 assert(fs->selected->size == 0);
3020 unifontsel_select_font(fs, fs->selected, size, 3, TRUE);
3024 static void alias_resolve(GtkTreeView *treeview, GtkTreePath *path,
3025 GtkTreeViewColumn *column, gpointer data)
3027 unifontsel_internal *fs = (unifontsel_internal *)data;
3029 int minval, newsize;
3030 fontinfo *info, *newinfo;
3033 if (fs->inhibit_response) /* we made this change ourselves */
3036 gtk_tree_model_get_iter(GTK_TREE_MODEL(fs->family_model), &iter, path);
3037 gtk_tree_model_get(GTK_TREE_MODEL(fs->family_model), &iter, 1,&minval, -1);
3038 info = (fontinfo *)index234(fs->fonts_by_selorder, minval);
3041 struct fontinfo_realname_find f;
3043 newname = info->fontclass->canonify_fontname
3044 (GTK_WIDGET(fs->u.window), info->realname, &newsize, &flags, TRUE);
3046 f.realname = newname;
3048 newinfo = find234(fs->fonts_by_realname, &f, fontinfo_realname_find);
3052 return; /* font name not in our index */
3053 if (newinfo == info)
3054 return; /* didn't change under canonification => not an alias */
3055 unifontsel_select_font(fs, newinfo,
3056 newinfo->size ? newinfo->size : newsize,
3061 #if GTK_CHECK_VERSION(3,0,0)
3062 static gint unifontsel_draw_area(GtkWidget *widget, cairo_t *cr, gpointer data)
3064 unifontsel_internal *fs = (unifontsel_internal *)data;
3065 unifont_drawctx dctx;
3067 dctx.type = DRAWTYPE_CAIRO;
3068 dctx.u.cairo.widget = widget;
3069 dctx.u.cairo.cr = cr;
3070 unifontsel_draw_preview_text_inner(&dctx, fs);
3075 static gint unifontsel_expose_area(GtkWidget *widget, GdkEventExpose *event,
3078 unifontsel_internal *fs = (unifontsel_internal *)data;
3080 #ifndef NO_BACKING_PIXMAPS
3081 if (fs->preview_pixmap) {
3082 gdk_draw_pixmap(gtk_widget_get_window(widget),
3083 (gtk_widget_get_style(widget)->fg_gc
3084 [gtk_widget_get_state(widget)]),
3086 event->area.x, event->area.y,
3087 event->area.x, event->area.y,
3088 event->area.width, event->area.height);
3091 unifontsel_draw_preview_text(fs);
3098 static gint unifontsel_configure_area(GtkWidget *widget,
3099 GdkEventConfigure *event, gpointer data)
3101 #ifndef NO_BACKING_PIXMAPS
3102 unifontsel_internal *fs = (unifontsel_internal *)data;
3103 int ox, oy, nx, ny, x, y;
3106 * Enlarge the pixmap, but never shrink it.
3108 ox = fs->preview_width;
3109 oy = fs->preview_height;
3112 if (x > ox || y > oy) {
3113 if (fs->preview_pixmap)
3114 gdk_pixmap_unref(fs->preview_pixmap);
3116 nx = (x > ox ? x : ox);
3117 ny = (y > oy ? y : oy);
3118 fs->preview_pixmap = gdk_pixmap_new(gtk_widget_get_window(widget),
3120 fs->preview_width = nx;
3121 fs->preview_height = ny;
3123 unifontsel_draw_preview_text(fs);
3127 gdk_window_invalidate_rect(gtk_widget_get_window(widget), NULL, FALSE);
3132 unifontsel *unifontsel_new(const char *wintitle)
3134 unifontsel_internal *fs = snew(unifontsel_internal);
3135 GtkWidget *table, *label, *w, *ww, *scroll;
3136 GtkListStore *model;
3137 GtkTreeViewColumn *column;
3138 int lists_height, preview_height, font_width, style_width, size_width;
3141 fs->inhibit_response = FALSE;
3142 fs->selected = NULL;
3148 * Invent some magic size constants.
3150 get_label_text_dimensions("Quite Long Font Name (Foundry)",
3153 lists_height = 14 * height;
3154 preview_height = 5 * height;
3156 get_label_text_dimensions("Italic Extra Condensed", &width, &height);
3157 style_width = width;
3159 get_label_text_dimensions("48000", &width, &height);
3164 * Create the dialog box and initialise the user-visible
3165 * fields in the returned structure.
3167 fs->u.user_data = NULL;
3168 fs->u.window = GTK_WINDOW(gtk_dialog_new());
3169 gtk_window_set_title(fs->u.window, wintitle);
3170 fs->u.cancel_button = gtk_dialog_add_button
3171 (GTK_DIALOG(fs->u.window), STANDARD_CANCEL_LABEL, GTK_RESPONSE_CANCEL);
3172 fs->u.ok_button = gtk_dialog_add_button
3173 (GTK_DIALOG(fs->u.window), STANDARD_OK_LABEL, GTK_RESPONSE_OK);
3174 gtk_widget_grab_default(fs->u.ok_button);
3177 * Now set up the internal fields, including in particular all
3178 * the controls that actually allow the user to select fonts.
3180 #if GTK_CHECK_VERSION(3,0,0)
3181 table = gtk_grid_new();
3182 gtk_grid_set_column_spacing(GTK_GRID(table), 8);
3184 table = gtk_table_new(8, 3, FALSE);
3185 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
3187 gtk_widget_show(table);
3189 #if GTK_CHECK_VERSION(3,0,0)
3190 /* GtkAlignment has become deprecated and we use the "margin"
3193 g_object_set(G_OBJECT(w), "margin", 8, (const char *)NULL);
3194 #elif GTK_CHECK_VERSION(2,4,0)
3195 /* GtkAlignment seems to be the simplest way to put padding round things */
3196 w = gtk_alignment_new(0, 0, 1, 1);
3197 gtk_alignment_set_padding(GTK_ALIGNMENT(w), 8, 8, 8, 8);
3198 gtk_container_add(GTK_CONTAINER(w), table);
3201 /* In GTK < 2.4, even that isn't available */
3205 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area
3206 (GTK_DIALOG(fs->u.window))),
3209 label = gtk_label_new_with_mnemonic("_Font:");
3210 gtk_widget_show(label);
3211 align_label_left(GTK_LABEL(label));
3212 #if GTK_CHECK_VERSION(3,0,0)
3213 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
3214 g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL);
3216 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
3220 * The Font list box displays only a string, but additionally
3221 * stores two integers which give the limits within the
3222 * tree234 of the font entries covered by this list entry.
3224 model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
3225 w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
3226 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE);
3227 gtk_label_set_mnemonic_widget(GTK_LABEL(label), w);
3229 column = gtk_tree_view_column_new_with_attributes
3230 ("Font", gtk_cell_renderer_text_new(),
3231 "text", 0, (char *)NULL);
3232 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
3233 gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
3234 g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(w))),
3235 "changed", G_CALLBACK(family_changed), fs);
3236 g_signal_connect(G_OBJECT(w), "row-activated",
3237 G_CALLBACK(alias_resolve), fs);
3239 scroll = gtk_scrolled_window_new(NULL, NULL);
3240 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
3242 gtk_container_add(GTK_CONTAINER(scroll), w);
3243 gtk_widget_show(scroll);
3244 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
3245 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3246 gtk_widget_set_size_request(scroll, font_width, lists_height);
3247 #if GTK_CHECK_VERSION(3,0,0)
3248 gtk_grid_attach(GTK_GRID(table), scroll, 0, 1, 1, 2);
3249 g_object_set(G_OBJECT(scroll), "expand", TRUE, (const char *)NULL);
3251 gtk_table_attach(GTK_TABLE(table), scroll, 0, 1, 1, 3, GTK_FILL,
3252 GTK_EXPAND | GTK_FILL, 0, 0);
3254 fs->family_model = model;
3255 fs->family_list = w;
3257 label = gtk_label_new_with_mnemonic("_Style:");
3258 gtk_widget_show(label);
3259 align_label_left(GTK_LABEL(label));
3260 #if GTK_CHECK_VERSION(3,0,0)
3261 gtk_grid_attach(GTK_GRID(table), label, 1, 0, 1, 1);
3262 g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL);
3264 gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
3268 * The Style list box can contain insensitive elements (character
3269 * set headings for server-side fonts), so we add an extra column
3270 * to the list store to hold that information. Also, since GTK3 at
3271 * least doesn't seem to display insensitive elements differently
3272 * by default, we add a further column to change their style.
3274 model = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT,
3275 G_TYPE_BOOLEAN, G_TYPE_INT);
3276 w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
3277 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE);
3278 gtk_label_set_mnemonic_widget(GTK_LABEL(label), w);
3280 column = gtk_tree_view_column_new_with_attributes
3281 ("Style", gtk_cell_renderer_text_new(),
3282 "text", 0, "sensitive", 3, "weight", 4, (char *)NULL);
3283 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
3284 gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
3285 g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(w))),
3286 "changed", G_CALLBACK(style_changed), fs);
3288 scroll = gtk_scrolled_window_new(NULL, NULL);
3289 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
3291 gtk_container_add(GTK_CONTAINER(scroll), w);
3292 gtk_widget_show(scroll);
3293 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
3294 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3295 gtk_widget_set_size_request(scroll, style_width, lists_height);
3296 #if GTK_CHECK_VERSION(3,0,0)
3297 gtk_grid_attach(GTK_GRID(table), scroll, 1, 1, 1, 2);
3298 g_object_set(G_OBJECT(scroll), "expand", TRUE, (const char *)NULL);
3300 gtk_table_attach(GTK_TABLE(table), scroll, 1, 2, 1, 3, GTK_FILL,
3301 GTK_EXPAND | GTK_FILL, 0, 0);
3303 fs->style_model = model;
3306 label = gtk_label_new_with_mnemonic("Si_ze:");
3307 gtk_widget_show(label);
3308 align_label_left(GTK_LABEL(label));
3309 #if GTK_CHECK_VERSION(3,0,0)
3310 gtk_grid_attach(GTK_GRID(table), label, 2, 0, 1, 1);
3311 g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL);
3313 gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
3317 * The Size label attaches primarily to a text input box so
3318 * that the user can select a size of their choice. The list
3319 * of available sizes is secondary.
3321 fs->size_entry = w = gtk_entry_new();
3322 gtk_label_set_mnemonic_widget(GTK_LABEL(label), w);
3323 gtk_widget_set_size_request(w, size_width, -1);
3325 #if GTK_CHECK_VERSION(3,0,0)
3326 gtk_grid_attach(GTK_GRID(table), w, 2, 1, 1, 1);
3327 g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3329 gtk_table_attach(GTK_TABLE(table), w, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
3331 g_signal_connect(G_OBJECT(w), "changed", G_CALLBACK(size_entry_changed),
3334 model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
3335 w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
3336 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE);
3338 column = gtk_tree_view_column_new_with_attributes
3339 ("Size", gtk_cell_renderer_text_new(),
3340 "text", 0, (char *)NULL);
3341 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
3342 gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
3343 g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(w))),
3344 "changed", G_CALLBACK(size_changed), fs);
3346 scroll = gtk_scrolled_window_new(NULL, NULL);
3347 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
3349 gtk_container_add(GTK_CONTAINER(scroll), w);
3350 gtk_widget_show(scroll);
3351 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
3352 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3353 #if GTK_CHECK_VERSION(3,0,0)
3354 gtk_grid_attach(GTK_GRID(table), scroll, 2, 2, 1, 1);
3355 g_object_set(G_OBJECT(scroll), "expand", TRUE, (const char *)NULL);
3357 gtk_table_attach(GTK_TABLE(table), scroll, 2, 3, 2, 3, GTK_FILL,
3358 GTK_EXPAND | GTK_FILL, 0, 0);
3360 fs->size_model = model;
3366 fs->preview_area = gtk_drawing_area_new();
3367 #ifndef NO_BACKING_PIXMAPS
3368 fs->preview_pixmap = NULL;
3370 fs->preview_width = 0;
3371 fs->preview_height = 0;
3372 fs->preview_fg.pixel = fs->preview_bg.pixel = 0;
3373 fs->preview_fg.red = fs->preview_fg.green = fs->preview_fg.blue = 0x0000;
3374 fs->preview_bg.red = fs->preview_bg.green = fs->preview_bg.blue = 0xFFFF;
3375 #if !GTK_CHECK_VERSION(3,0,0)
3376 gdk_colormap_alloc_color(gdk_colormap_get_system(), &fs->preview_fg,
3378 gdk_colormap_alloc_color(gdk_colormap_get_system(), &fs->preview_bg,
3381 #if GTK_CHECK_VERSION(3,0,0)
3382 g_signal_connect(G_OBJECT(fs->preview_area), "draw",
3383 G_CALLBACK(unifontsel_draw_area), fs);
3385 g_signal_connect(G_OBJECT(fs->preview_area), "expose_event",
3386 G_CALLBACK(unifontsel_expose_area), fs);
3388 g_signal_connect(G_OBJECT(fs->preview_area), "configure_event",
3389 G_CALLBACK(unifontsel_configure_area), fs);
3390 gtk_widget_set_size_request(fs->preview_area, 1, preview_height);
3391 gtk_widget_show(fs->preview_area);
3392 ww = fs->preview_area;
3393 w = gtk_frame_new(NULL);
3394 gtk_container_add(GTK_CONTAINER(w), ww);
3397 #if GTK_CHECK_VERSION(3,0,0)
3398 /* GtkAlignment has become deprecated and we use the "margin"
3400 g_object_set(G_OBJECT(w), "margin", 8, (const char *)NULL);
3401 #elif GTK_CHECK_VERSION(2,4,0)
3403 /* GtkAlignment seems to be the simplest way to put padding round things */
3404 w = gtk_alignment_new(0, 0, 1, 1);
3405 gtk_alignment_set_padding(GTK_ALIGNMENT(w), 8, 8, 8, 8);
3406 gtk_container_add(GTK_CONTAINER(w), ww);
3411 w = gtk_frame_new("Preview of font");
3412 gtk_container_add(GTK_CONTAINER(w), ww);
3414 #if GTK_CHECK_VERSION(3,0,0)
3415 gtk_grid_attach(GTK_GRID(table), w, 0, 3, 3, 1);
3416 g_object_set(G_OBJECT(w), "expand", TRUE, (const char *)NULL);
3418 gtk_table_attach(GTK_TABLE(table), w, 0, 3, 3, 4,
3419 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 8);
3423 * We only provide the checkboxes for client- and server-side
3424 * fonts if we have the X11 back end available, because that's the
3425 * only situation in which more than one class of font is
3428 fs->n_filter_buttons = 0;
3429 #ifndef NOT_X_WINDOWS
3430 w = gtk_check_button_new_with_label("Show client-side fonts");
3431 g_object_set_data(G_OBJECT(w), "user-data",
3432 GINT_TO_POINTER(FONTFLAG_CLIENTSIDE));
3433 g_signal_connect(G_OBJECT(w), "toggled",
3434 G_CALLBACK(unifontsel_button_toggled), fs);
3436 fs->filter_buttons[fs->n_filter_buttons++] = w;
3437 #if GTK_CHECK_VERSION(3,0,0)
3438 gtk_grid_attach(GTK_GRID(table), w, 0, 4, 3, 1);
3439 g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3441 gtk_table_attach(GTK_TABLE(table), w, 0, 3, 4, 5, GTK_FILL, 0, 0, 0);
3443 w = gtk_check_button_new_with_label("Show server-side fonts");
3444 g_object_set_data(G_OBJECT(w), "user-data",
3445 GINT_TO_POINTER(FONTFLAG_SERVERSIDE));
3446 g_signal_connect(G_OBJECT(w), "toggled",
3447 G_CALLBACK(unifontsel_button_toggled), fs);
3449 fs->filter_buttons[fs->n_filter_buttons++] = w;
3450 #if GTK_CHECK_VERSION(3,0,0)
3451 gtk_grid_attach(GTK_GRID(table), w, 0, 5, 3, 1);
3452 g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3454 gtk_table_attach(GTK_TABLE(table), w, 0, 3, 5, 6, GTK_FILL, 0, 0, 0);
3456 w = gtk_check_button_new_with_label("Show server-side font aliases");
3457 g_object_set_data(G_OBJECT(w), "user-data",
3458 GINT_TO_POINTER(FONTFLAG_SERVERALIAS));
3459 g_signal_connect(G_OBJECT(w), "toggled",
3460 G_CALLBACK(unifontsel_button_toggled), fs);
3462 fs->filter_buttons[fs->n_filter_buttons++] = w;
3463 #if GTK_CHECK_VERSION(3,0,0)
3464 gtk_grid_attach(GTK_GRID(table), w, 0, 6, 3, 1);
3465 g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3467 gtk_table_attach(GTK_TABLE(table), w, 0, 3, 6, 7, GTK_FILL, 0, 0, 0);
3469 #endif /* NOT_X_WINDOWS */
3470 w = gtk_check_button_new_with_label("Show non-monospaced fonts");
3471 g_object_set_data(G_OBJECT(w), "user-data",
3472 GINT_TO_POINTER(FONTFLAG_NONMONOSPACED));
3473 g_signal_connect(G_OBJECT(w), "toggled",
3474 G_CALLBACK(unifontsel_button_toggled), fs);
3476 fs->filter_buttons[fs->n_filter_buttons++] = w;
3477 #if GTK_CHECK_VERSION(3,0,0)
3478 gtk_grid_attach(GTK_GRID(table), w, 0, 7, 3, 1);
3479 g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
3481 gtk_table_attach(GTK_TABLE(table), w, 0, 3, 7, 8, GTK_FILL, 0, 0, 0);
3484 assert(fs->n_filter_buttons <= lenof(fs->filter_buttons));
3485 fs->filter_flags = FONTFLAG_CLIENTSIDE | FONTFLAG_SERVERSIDE |
3486 FONTFLAG_SERVERALIAS;
3487 unifontsel_set_filter_buttons(fs);
3490 * Go and find all the font names, and set up our master font
3493 fs->fonts_by_realname = newtree234(fontinfo_realname_compare);
3494 fs->fonts_by_selorder = newtree234(fontinfo_selorder_compare);
3495 for (i = 0; i < lenof(unifont_types); i++)
3496 unifont_types[i]->enum_fonts(GTK_WIDGET(fs->u.window),
3497 unifontsel_add_entry, fs);
3500 * And set up the initial font names list.
3502 unifontsel_setup_familylist(fs);
3504 fs->selsize = fs->intendedsize = 13; /* random default */
3505 gtk_widget_set_sensitive(fs->u.ok_button, FALSE);
3507 return (unifontsel *)fs;
3510 void unifontsel_destroy(unifontsel *fontsel)
3512 unifontsel_internal *fs = (unifontsel_internal *)fontsel;
3515 #ifndef NO_BACKING_PIXMAPS
3516 if (fs->preview_pixmap)
3517 gdk_pixmap_unref(fs->preview_pixmap);
3520 freetree234(fs->fonts_by_selorder);
3521 while ((info = delpos234(fs->fonts_by_realname, 0)) != NULL)
3523 freetree234(fs->fonts_by_realname);
3525 gtk_widget_destroy(GTK_WIDGET(fs->u.window));
3529 void unifontsel_set_name(unifontsel *fontsel, const char *fontname)
3531 unifontsel_internal *fs = (unifontsel_internal *)fontsel;
3532 int i, start, end, size, flags;
3533 const char *fontname2 = NULL;
3537 * Provide a default if given an empty or null font name.
3539 if (!fontname || !*fontname)
3540 fontname = DEFAULT_GTK_FONT;
3543 * Call the canonify_fontname function.
3545 fontname = unifont_do_prefix(fontname, &start, &end);
3546 for (i = start; i < end; i++) {
3547 fontname2 = unifont_types[i]->canonify_fontname
3548 (GTK_WIDGET(fs->u.window), fontname, &size, &flags, FALSE);
3553 return; /* font name not recognised */
3556 * Now look up the canonified font name in our index.
3559 struct fontinfo_realname_find f;
3560 f.realname = fontname2;
3562 info = find234(fs->fonts_by_realname, &f, fontinfo_realname_find);
3566 * If we've found the font, and its size field is either
3567 * correct or zero (the latter indicating a scalable font),
3568 * then we're done. Otherwise, try looking up the original
3569 * font name instead.
3571 if (!info || (info->size != size && info->size != 0)) {
3572 struct fontinfo_realname_find f;
3573 f.realname = fontname;
3576 info = find234(fs->fonts_by_realname, &f, fontinfo_realname_find);
3577 if (!info || info->size != size)
3578 return; /* font name not in our index */
3582 * Now we've got a fontinfo structure and a font size, so we
3583 * know everything we need to fill in all the fields in the
3586 unifontsel_select_font(fs, info, size, 0, TRUE);
3589 char *unifontsel_get_name(unifontsel *fontsel)
3591 unifontsel_internal *fs = (unifontsel_internal *)fontsel;
3597 if (fs->selected->size == 0) {
3598 name = fs->selected->fontclass->scale_fontname
3599 (GTK_WIDGET(fs->u.window), fs->selected->realname, fs->selsize);
3601 char *ret = dupcat(fs->selected->fontclass->prefix, ":",
3608 return dupcat(fs->selected->fontclass->prefix, ":",
3609 fs->selected->realname, NULL);
3612 #endif /* GTK_CHECK_VERSION(2,0,0) */