42
42
#include <X11/Xlocale.h>
45
#ifdef HAVE_X11_XFT_XFT_H
46
# include <X11/Xft/Xft.h>
53
# define PANGO_ENABLE_BACKEND
54
# include <pango/pango.h>
55
# undef PANGO_ENABLE_BACKEND
57
# include <pango/pangox.h>
59
# ifdef HAVE_PANGO_XFT
60
# define PANGO_ENABLE_ENGINE
61
# include <pango/pangoxft.h>
62
# undef PANGO_ENABLE_ENGINE
45
66
static Lisp_Font *font_list;
48
69
DEFSYM(default_font, "default-font");
50
static XFontSet x_create_font_set (char *xlfd, char ***missing,
51
int *nmissing, char **def_string);
54
DEFUN("get-font", Fget_font, Sget_font, (repv name), rep_Subr1) /*
55
::doc:sawfish.wm.fonts#get-font::
58
Return the font object representing the font named NAME (a standard X
59
font specifier string).
63
rep_DECLARE1(name, rep_STRINGP);
69
while (f != 0 && strcmp (rep_STR(name), rep_STR(f->name)) != 0)
73
repv tem = global_symbol_value (Qfonts_are_fontsets);
75
XFontSet font_set = 0;
76
XFontStruct *font_struct = 0;
78
char **missing_charset_list, *def_string;
79
int num_missing_charset_list;
83
font_set = x_create_font_set (rep_STR(name),
84
&missing_charset_list,
85
&num_missing_charset_list,
93
num_fonts = XFontsOfFontSet (font_set, &fstrs, &font_names);
95
for (i = 0; i < num_fonts; i++)
97
if (fstrs[i]->ascent > ascent)
98
ascent = fstrs[i]->ascent;
99
if (fstrs[i]->descent > descent)
100
descent = fstrs[i]->descent;
102
if (num_missing_charset_list > 0)
105
fprintf (stderr, "Missing charsets in FontSet creation\n");
106
for (i = 0; i < num_missing_charset_list; i++)
107
fprintf (stderr, "\t%s\n", missing_charset_list[i]);
108
XFreeStringList (missing_charset_list);
113
/* can't load a FontSet, try falling back to a FontStruct */
115
font_struct = XLoadQueryFont (dpy, rep_STR (name));
116
if (font_struct != 0)
118
ascent = font_struct->ascent;
119
descent = font_struct->descent;
123
return Fsignal (Qerror,
124
rep_list_2 (rep_string_dup("no such font"),
129
f = rep_ALLOC_CELL(sizeof(Lisp_Font));
130
rep_data_after_gc += sizeof (Lisp_Font);
137
f->descent = descent;
139
f->font.set = font_set;
142
f->font.str = font_struct;
143
f->car |= FF_FONT_STRUCT;
149
DEFUN("font-get", Ffont_get, Sfont_get, (repv win, repv prop), rep_Subr2) /*
150
::doc:sawfish.wm.fonts#font-get::
151
font-get FONT PROPERTY
153
Return the property PROPERTY (a symbol) associated with FONT.
157
rep_DECLARE1(win, FONTP);
158
plist = VFONT(win)->plist;
159
while (rep_CONSP(plist) && rep_CONSP(rep_CDR(plist)))
161
if (rep_CAR(plist) == prop
162
|| (!rep_SYMBOLP(prop)
163
&& rep_value_cmp (rep_CAR(plist), prop) == 0))
165
return rep_CAR(rep_CDR(plist));
167
plist = rep_CDR(rep_CDR(plist));
172
DEFUN("font-put", Ffont_put, Sfont_put, (repv win, repv prop, repv val), rep_Subr3) /*
173
::doc:sawfish.wm.fonts#font-put::
174
font-put FONT PROPERTY VALUE
176
Set the property PROPERTY (a symbol) associated with FONT to VALUE.
180
rep_DECLARE1(win, FONTP);
181
plist = VFONT(win)->plist;
182
while (rep_CONSP(plist) && rep_CONSP(rep_CDR(plist)))
184
if (rep_CAR(plist) == prop
185
|| (!rep_SYMBOLP(prop)
186
&& rep_value_cmp (rep_CAR(plist), prop) == 0))
188
rep_CAR(rep_CDR(plist)) = val;
191
plist = rep_CDR(rep_CDR(plist));
193
plist = Fcons(prop, Fcons(val, VFONT(win)->plist));
194
if (plist != rep_NULL)
195
VFONT(win)->plist = plist;
199
DEFUN("font-name", Ffont_name, Sfont_name, (repv font), rep_Subr1) /*
200
::doc:sawfish.wm.fonts#font-name::
203
Return the name of the font represented by the font object FONT.
206
rep_DECLARE1(font, FONTP);
207
return VFONT(font)->name;
210
DEFUN("fontp", Ffontp, Sfontp, (repv win), rep_Subr1) /*
211
::doc:sawfish.wm.fonts#fontp::
214
Return t if ARG is a font object.
217
return FONTP(win) ? Qt : Qnil;
221
x_text_width (repv font, u_char *string, size_t len)
223
if (FONT_STRUCT_P (font))
224
return XTextWidth (VFONT(font)->font.str, string, len);
226
return XmbTextEscapement (VFONT(font)->font.set, string, len);
230
x_draw_string (Window id, repv font, GC gc,
231
int x, int y, u_char *string, size_t len)
233
if (FONT_STRUCT_P (font))
235
XSetFont (dpy, gc, VFONT(font)->font.str->fid);
236
XDrawString (dpy, id, gc, x, y, string, len);
239
XmbDrawString (dpy, id, VFONT(font)->font.set, gc, x, y, string, len);
242
DEFUN("text-width", Ftext_width, Stext_width, (repv string, repv font), rep_Subr2) /*
243
::doc:sawfish.wm.fonts#text-width::
244
text-width STRING [FONT]
246
Return the number of horizontal pixels that would be required to display
247
the text STRING using font object FONT (or the default-font).
250
rep_DECLARE1(string, rep_STRINGP);
252
font = global_symbol_value (Qdefault_font);
253
rep_DECLARE2(font, FONTP);
254
return rep_MAKE_INT (x_text_width (font, rep_STR(string),
255
rep_STRING_LEN(string)));
258
DEFUN("font-height", Ffont_height, Sfont_height, (repv font), rep_Subr1) /*
259
::doc:sawfish.wm.fonts#font-height::
262
Return the bounding height of glyphs rendered using FONT (or the
267
font = global_symbol_value (Qdefault_font);
268
rep_DECLARE1(font, FONTP);
269
return rep_MAKE_INT(VFONT(font)->ascent + VFONT(font)->descent);
272
DEFUN("font-ascent", Ffont_ascent, Sfont_ascent, (repv font), rep_Subr1) /*
273
::doc:sawfish.wm.fonts#font-ascent::
276
Return the ascent of glyphs rendered using FONT (or the
281
font = global_symbol_value (Qdefault_font);
282
rep_DECLARE1(font, FONTP);
283
return rep_MAKE_INT(VFONT(font)->ascent);
286
DEFUN("font-descent", Ffont_descent, Sfont_descent, (repv font), rep_Subr1) /*
287
::doc:sawfish.wm.fonts#font-descent::
290
Return the descent of glyphs rendered using FONT (or the
295
font = global_symbol_value (Qdefault_font);
296
rep_DECLARE1(font, FONTP);
297
return rep_MAKE_INT(VFONT(font)->descent);
301
/* XLFD pattern matching */
71
struct Lisp_Font_Class_struct {
73
bool (*load) (Lisp_Font *f);
74
void (*finalize) (Lisp_Font *f);
75
int (*measure) (Lisp_Font *f, u_char *string, size_t length);
76
void (*draw) (Lisp_Font *f, u_char *string, size_t length,
77
Window id, GC gc, Lisp_Color *fg, int x, int y);
81
/* Xlib font structs */
84
fontstruct_load (Lisp_Font *f)
86
XFontStruct *font_struct;
88
font_struct = XLoadQueryFont (dpy, rep_STR (f->name));
93
f->font = font_struct;
94
f->ascent = font_struct->ascent;
95
f->descent = font_struct->descent;
101
fontstruct_finalize (Lisp_Font *f)
103
XFreeFont (dpy, f->font);
107
fontstruct_measure (Lisp_Font *f, u_char *string, size_t length)
109
return XTextWidth (f->font, string, length);
113
fontstruct_draw (Lisp_Font *f, u_char *string, size_t length,
114
Window id, GC gc, Lisp_Color *fg, int x, int y)
121
gcv.foreground = fg->pixel;
123
XChangeGC (dpy, gc, GCForeground | GCFont, &gcv);
125
XDrawString (dpy, id, gc, x, y, string, length);
128
static const Lisp_Font_Class fontstruct_class = {
130
fontstruct_load, fontstruct_finalize,
131
fontstruct_measure, fontstruct_draw,
304
138
xlfd_get_element (const char *xlfd, int idx)
259
fontset_load (Lisp_Font *f)
264
char **missing_charset_list, *def_string;
265
int num_missing_charset_list;
267
font_set = x_create_fontset (rep_STR (f->name),
268
&missing_charset_list,
269
&num_missing_charset_list,
280
num_fonts = XFontsOfFontSet (font_set, &fstrs, &font_names);
281
ascent = descent = 0;
283
for (i = 0; i < num_fonts; i++)
285
if (fstrs[i]->ascent > ascent)
286
f->ascent = fstrs[i]->ascent;
287
if (fstrs[i]->descent > descent)
288
f->descent = fstrs[i]->descent;
291
if (num_missing_charset_list > 0)
293
fprintf (stderr, "Missing charsets in FontSet creation\n");
294
for (j = 0; j < num_missing_charset_list; j++)
295
fprintf (stderr, "\t%s\n", missing_charset_list[j]);
296
XFreeStringList (missing_charset_list);
306
fontset_finalize (Lisp_Font *f)
308
XFreeFontSet (dpy, f->font);
312
fontset_measure (Lisp_Font *f, u_char *string, size_t length)
314
return XmbTextEscapement (f->font, string, length);
318
fontset_draw (Lisp_Font *f, u_char *string, size_t length,
319
Window id, GC gc, Lisp_Color *fg, int x, int y)
323
gcv.foreground = fg->pixel;
324
XChangeGC (dpy, gc, GCForeground, &gcv);
326
XmbDrawString (dpy, id, f->font, gc, x, y, string, length);
329
static const Lisp_Font_Class fontset_class = {
331
fontset_load, fontset_finalize,
332
fontset_measure, fontset_draw,
338
#ifdef HAVE_X11_XFT_XFT_H
341
xft_load (Lisp_Font *f)
345
xft_font = XftFontOpenName (dpy, screen_num, rep_STR (f->name));
351
f->ascent = xft_font->ascent;
352
f->descent = xft_font->descent;
358
xft_finalize (Lisp_Font *f)
360
XftFontClose (dpy, f->font);
364
xft_measure (Lisp_Font *f, u_char *string, size_t length)
368
XftTextExtents8 (dpy, f->font, string, length, &info);
374
xft_draw (Lisp_Font *f, u_char *string, size_t length,
375
Window id, GC gc, Lisp_Color *fg, int x, int y)
377
static XftDraw *draw;
382
draw = XftDrawCreate (dpy, id, image_visual, image_cmap);
384
XftDrawChange (draw, id);
386
xft_color.pixel = fg->pixel;
387
xft_color.color.red = fg->red;
388
xft_color.color.green = fg->green;
389
xft_color.color.blue = fg->blue;
390
xft_color.color.alpha = fg->alpha;
392
XftDrawString8 (draw, &xft_color, f->font,
393
x, y, string, length);
396
static const Lisp_Font_Class xft_class = {
398
xft_load, xft_finalize,
399
xft_measure, xft_draw,
402
#endif /* HAVE_X11_XFT_XFT_H */
409
static PangoContext *pango_context;
412
pango_load (Lisp_Font *f)
414
PangoLanguage *language;
415
PangoFontDescription *fontdesc;
417
PangoFontMetrics *metrics;
421
language = pango_context_get_language (pango_context);
427
#ifdef HAVE_PANGO_XFT
428
pango_context = pango_xft_get_context (dpy, screen_num);
430
pango_context = pango_x_get_context (dpy, screen_num);
433
langname = g_strdup (setlocale (LC_CTYPE, NULL));
434
p = strchr (langname, '.');
437
p = strchr (langname, '@');
440
language = pango_language_from_string (langname);
441
pango_context_set_language (pango_context, language);
445
fontdesc = pango_font_description_from_string (rep_STR (f->name));
447
if (!pango_font_description_get_family (fontdesc))
448
pango_font_description_set_family (fontdesc, "Sans");
449
if (pango_font_description_get_size (fontdesc) <= 0)
450
pango_font_description_set_size (fontdesc, 12 * PANGO_SCALE);
452
pango_context_set_font_description (pango_context, fontdesc);
453
font = pango_context_load_font (pango_context, fontdesc);
458
metrics = pango_font_get_metrics (font, language);
461
f->ascent = metrics->ascent / PANGO_SCALE;
462
f->descent = metrics->descent / PANGO_SCALE;
464
pango_font_metrics_unref (metrics);
470
pango_finalize (Lisp_Font *f)
472
g_object_unref (f->font);
476
pango_measure (Lisp_Font *f, u_char *string, size_t length)
483
utf8str = g_locale_to_utf8 (string, length, &r, &w, NULL);
490
layout = pango_layout_new (pango_context);
491
pango_layout_set_text (layout, string, length);
493
pango_layout_get_extents (layout, NULL, &rect);
496
g_object_unref (layout);
498
return rect.width / PANGO_SCALE;
502
pango_draw_line (XftDraw *draw, Window id, GC gc, XftColor *xft_color,
503
PangoLayoutLine *line, int x, int y)
507
for (p = line->runs; p != NULL; p = p->next)
509
PangoLayoutRun *run = p->data;
510
PangoFont *font = run->item->analysis.font;
511
PangoGlyphString *glyphs = run->glyphs;
514
pango_glyph_string_extents (glyphs, font, NULL, &rect);
515
#ifdef HAVE_PANGO_XFT
516
if (PANGO_XFT_IS_FONT (font))
517
pango_xft_render (draw, xft_color, font, glyphs, x, y);
520
pango_x_render (dpy, id, gc, font, glyphs, x, y);
522
x += rect.width / PANGO_SCALE;
527
pango_draw (Lisp_Font *f, u_char *string, size_t length,
528
Window id, GC gc, Lisp_Color *fg, int x, int y)
530
static XftDraw *draw;
535
PangoLayoutIter *iter;
538
draw = XftDrawCreate (dpy, id, image_visual, image_cmap);
540
XftDrawChange (draw, id);
542
xft_color.pixel = fg->pixel;
543
xft_color.color.red = fg->red;
544
xft_color.color.green = fg->green;
545
xft_color.color.blue = fg->blue;
546
xft_color.color.alpha = fg->alpha;
548
utf8str = g_locale_to_utf8 (string, length, &r, &w, NULL);
555
layout = pango_layout_new (pango_context);
556
pango_layout_set_text (layout, string, length);
557
iter = pango_layout_get_iter (layout);
560
PangoLayoutLine *line = pango_layout_iter_get_line (iter);
563
pango_layout_iter_get_line_extents (iter, NULL, &rect);
564
pango_draw_line (draw, id, gc, &xft_color,
565
line, x + rect.x / PANGO_SCALE, y);
566
} while (pango_layout_iter_next_line (iter));
569
g_object_unref (layout);
570
pango_layout_iter_free (iter);
573
static const Lisp_Font_Class pango_class = {
575
pango_load, pango_finalize,
576
pango_measure, pango_draw,
579
#endif /* HAVE_PANGO */
584
static const Lisp_Font_Class *classes[] = {
587
#ifdef HAVE_X11_XFT_XFT_H
599
DEFUN ("font-type-exists-p", Ffont_type_exists_p,
600
Sfont_type_exists_p, (repv type), rep_Subr1) /*
601
::doc:sawfish.wm.fonts#font-type-exists-p::
602
font-type-exists-p TYPE
604
Returns true if fonts with the type described by the string TYPE can be
610
rep_DECLARE1 (type, rep_STRINGP);
612
for (i = 0; classes[i] != 0; i++)
614
if (strcasecmp (rep_STR (type), classes[i]->type) == 0)
621
DEFUN("get-font-typed", Fget_font_typed, Sget_font_typed,
622
(repv type, repv name), rep_Subr2) /*
623
::doc:sawfish.wm.fonts#get-font-typed::
624
get-font-typed TYPE NAME
626
Return the font object representing the font named NAME. NAME is
627
interpreted based on the value of the string TYPE.
631
const Lisp_Font_Class *class;
635
rep_DECLARE1(name, rep_STRINGP);
636
rep_DECLARE2(type, rep_STRINGP);
641
for (f = font_list; f != NULL; f = f->next)
643
if (strcmp (rep_STR(name), rep_STR(f->name)) == 0
644
&& strcmp (rep_STR (type), rep_STR (f->type)) == 0)
652
if (strcasecmp (rep_STR (type), "xlfd") == 0)
654
/* Boring old X core fonts */
656
tem = global_symbol_value (Qfonts_are_fontsets);
658
class = &fontset_class;
660
class = &fontstruct_class;
664
for (i = 0; classes[i] != 0; i++)
666
if (strcasecmp (rep_STR (type), classes[i]->type) == 0)
676
DEFSTRING (err, "unknown font type");
677
return Fsignal (Qerror, rep_list_2 (rep_VAL (&err), type));
680
f = rep_ALLOC_CELL(sizeof(Lisp_Font));
688
if (!(*class->load) (f))
690
DEFSTRING (err, "unknown font");
693
return Fsignal (Qerror, rep_list_2 (rep_VAL (&err), name));
696
rep_data_after_gc += sizeof (Lisp_Font);
704
DEFUN("get-font", Fget_font, Sget_font, (repv name), rep_Subr1) /*
705
::doc:sawfish.wm.fonts#get-font::
708
Return the font object representing the font named NAME (a standard X
709
font specifier string).
712
DEFSTRING (type, "xlfd");
714
return Fget_font_typed (rep_VAL (&type), name);
717
DEFUN("font-get", Ffont_get, Sfont_get, (repv win, repv prop), rep_Subr2) /*
718
::doc:sawfish.wm.fonts#font-get::
719
font-get FONT PROPERTY
721
Return the property PROPERTY (a symbol) associated with FONT.
725
rep_DECLARE1(win, FONTP);
726
plist = VFONT(win)->plist;
727
while (rep_CONSP(plist) && rep_CONSP(rep_CDR(plist)))
729
if (rep_CAR(plist) == prop
730
|| (!rep_SYMBOLP(prop)
731
&& rep_value_cmp (rep_CAR(plist), prop) == 0))
733
return rep_CAR(rep_CDR(plist));
735
plist = rep_CDR(rep_CDR(plist));
740
DEFUN("font-put", Ffont_put, Sfont_put, (repv win, repv prop, repv val), rep_Subr3) /*
741
::doc:sawfish.wm.fonts#font-put::
742
font-put FONT PROPERTY VALUE
744
Set the property PROPERTY (a symbol) associated with FONT to VALUE.
748
rep_DECLARE1(win, FONTP);
749
plist = VFONT(win)->plist;
750
while (rep_CONSP(plist) && rep_CONSP(rep_CDR(plist)))
752
if (rep_CAR(plist) == prop
753
|| (!rep_SYMBOLP(prop)
754
&& rep_value_cmp (rep_CAR(plist), prop) == 0))
756
rep_CAR(rep_CDR(plist)) = val;
759
plist = rep_CDR(rep_CDR(plist));
761
plist = Fcons(prop, Fcons(val, VFONT(win)->plist));
762
if (plist != rep_NULL)
763
VFONT(win)->plist = plist;
767
DEFUN("font-type", Ffont_type, Sfont_type, (repv font), rep_Subr1) /*
768
::doc:sawfish.wm.fonts#font-type::
771
Return the type of the font represented by the font object FONT.
774
rep_DECLARE1(font, FONTP);
775
return VFONT(font)->type;
778
DEFUN("font-name", Ffont_name, Sfont_name, (repv font), rep_Subr1) /*
779
::doc:sawfish.wm.fonts#font-name::
782
Return the name of the font represented by the font object FONT.
785
rep_DECLARE1(font, FONTP);
786
return VFONT(font)->name;
789
DEFUN("fontp", Ffontp, Sfontp, (repv win), rep_Subr1) /*
790
::doc:sawfish.wm.fonts#fontp::
793
Return t if ARG is a font object.
796
return FONTP(win) ? Qt : Qnil;
800
x_text_width (repv font, u_char *string, size_t len)
802
return (*VFONT (font)->class->measure) (VFONT (font), string, len);
805
/* The foreground pixel of GC is undefined after this function returns. */
807
x_draw_string (Window id, repv font, GC gc, Lisp_Color *fg_color,
808
int x, int y, u_char *string, size_t len)
810
(*VFONT (font)->class->draw) (VFONT (font), string, len,
811
id, gc, fg_color, x, y);
814
DEFUN("text-width", Ftext_width, Stext_width, (repv string, repv font), rep_Subr2) /*
815
::doc:sawfish.wm.fonts#text-width::
816
text-width STRING [FONT]
818
Return the number of horizontal pixels that would be required to display
819
the text STRING using font object FONT (or the default-font).
822
rep_DECLARE1(string, rep_STRINGP);
824
font = global_symbol_value (Qdefault_font);
825
rep_DECLARE2(font, FONTP);
826
return rep_MAKE_INT (x_text_width (font, rep_STR(string),
827
rep_STRING_LEN(string)));
830
DEFUN("font-height", Ffont_height, Sfont_height, (repv font), rep_Subr1) /*
831
::doc:sawfish.wm.fonts#font-height::
834
Return the bounding height of glyphs rendered using FONT (or the
839
font = global_symbol_value (Qdefault_font);
840
rep_DECLARE1(font, FONTP);
841
return rep_MAKE_INT(VFONT(font)->ascent + VFONT(font)->descent);
844
DEFUN("font-ascent", Ffont_ascent, Sfont_ascent, (repv font), rep_Subr1) /*
845
::doc:sawfish.wm.fonts#font-ascent::
848
Return the ascent of glyphs rendered using FONT (or the
853
font = global_symbol_value (Qdefault_font);
854
rep_DECLARE1(font, FONTP);
855
return rep_MAKE_INT(VFONT(font)->ascent);
858
DEFUN("font-descent", Ffont_descent, Sfont_descent, (repv font), rep_Subr1) /*
859
::doc:sawfish.wm.fonts#font-descent::
862
Return the descent of glyphs rendered using FONT (or the
867
font = global_symbol_value (Qdefault_font);
868
rep_DECLARE1(font, FONTP);
869
return rep_MAKE_INT(VFONT(font)->descent);