put the render theme into a struct
[mikachu/openbox.git] / render / font.c
1 #include "font.h"
2 #include "theme.h"
3 #include "kernel/geom.h"
4 #include "kernel/gettext.h"
5 #define _(str) gettext(str)
6
7 #include <X11/Xft/Xft.h>
8 #include <glib.h>
9 #include <string.h>
10
11 #define ELIPSES "..."
12 #define ELIPSES_LENGTH(font, shadow, offset) \
13     (font->elipses_length + (shadow ? offset : 0))
14
15 void font_startup(void)
16 {
17 #ifdef DEBUG
18     int version;
19 #endif /* DEBUG */
20     if (!XftInit(0)) {
21         g_warning(_("Couldn't initialize Xft.\n"));
22         exit(3);
23     }
24 #ifdef DEBUG
25     version = XftGetVersion();
26     g_message("Using Xft %d.%d.%d (Built against %d.%d.%d).",
27               version / 10000 % 100, version / 100 % 100, version % 100,
28               XFT_MAJOR, XFT_MINOR, XFT_REVISION);
29 #endif
30 }
31
32 static void measure_height(RrFont *f)
33 {
34     XGlyphInfo info;
35
36     /* measure an elipses */
37     XftTextExtentsUtf8(RrDisplay(f->inst), f->xftfont,
38                        (FcChar8*)ELIPSES, strlen(ELIPSES), &info);
39     f->elipses_length = (signed) info.xOff;
40 }
41
42 RrFont *font_open(const RrInstance *inst, char *fontstring)
43 {
44     RrFont *out;
45     XftFont *xf;
46     
47     if ((xf = XftFontOpenName(RrDisplay(inst), RrScreen(inst), fontstring))) {
48         out = g_new(RrFont, 1);
49         out->inst = inst;
50         out->xftfont = xf;
51         measure_height(out);
52         return out;
53     }
54     g_warning(_("Unable to load font: %s\n"), fontstring);
55     g_warning(_("Trying fallback font: %s\n"), "sans");
56
57     if ((xf = XftFontOpenName(RrDisplay(inst), RrScreen(inst), "sans"))) {
58         out = g_new(RrFont, 1);
59         out->inst = inst;
60         out->xftfont = xf;
61         measure_height(out);
62         return out;
63     }
64     g_warning(_("Unable to load font: %s\n"), "sans");
65     g_warning(_("Aborting!.\n"));
66
67     exit(3); /* can't continue without a font */
68 }
69
70 void font_close(RrFont *f)
71 {
72     if (f) {
73         XftFontClose(RrDisplay(f->inst), f->xftfont);
74         g_free(f);
75     }
76 }
77
78 void font_measure_full(RrFont *f, char *str, int shadow, int offset,
79                        int *x, int *y)
80 {
81     XGlyphInfo info;
82
83     XftTextExtentsUtf8(RrDisplay(f->inst), f->xftfont,
84                        (FcChar8*)str, strlen(str), &info);
85
86     *x = (signed) info.xOff + (shadow ? ABS(offset) : 0);
87     *y = info.height + (shadow ? ABS(offset) : 0);
88 }
89
90 int font_measure_string(RrFont *f, char *str, int shadow, int offset)
91 {
92     int x, y;
93     font_measure_full (f, str, shadow, offset, &x, &y);
94     return x;
95 }
96
97 int font_height(RrFont *f, int shadow, int offset)
98 {
99     return f->xftfont->ascent + f->xftfont->descent + (shadow ? offset : 0);
100 }
101
102 int font_max_char_width(RrFont *f)
103 {
104     return (signed) f->xftfont->max_advance_width;
105 }
106
107 void font_draw(XftDraw *d, RrTextureText *t, Rect *area)
108 {
109     int x,y,w,h;
110     XftColor c;
111     GString *text;
112     int mw, em, mh;
113     size_t l;
114     gboolean shortened = FALSE;
115
116     /* center vertically */
117     y = area->y +
118         (area->height - font_height(t->font, t->shadow, t->offset)) / 2;
119     w = area->width;
120     h = area->height;
121
122     text = g_string_new(t->string);
123     l = g_utf8_strlen(text->str, -1);
124     font_measure_full(t->font, text->str, t->shadow, t->offset, &mw, &mh);
125     while (l && mw > area->width) {
126         shortened = TRUE;
127         /* remove a character from the middle */
128         text = g_string_erase(text, l-- / 2, 1);
129         em = ELIPSES_LENGTH(t->font, t->shadow, t->offset);
130         /* if the elipses are too large, don't show them at all */
131         if (em > area->width)
132             shortened = FALSE;
133         font_measure_full(t->font, text->str, t->shadow, t->offset, &mw, &mh);
134         mw += em;
135     }
136     if (shortened) {
137         text = g_string_insert(text, (l + 1) / 2, ELIPSES);
138         l += 3;
139     }
140     if (!l) return;
141
142     switch (t->justify) {
143     case RR_JUSTIFY_LEFT:
144         x = area->x;
145         break;
146     case RR_JUSTIFY_RIGHT:
147         x = area->x + (w - mw);
148         break;
149     case RR_JUSTIFY_CENTER:
150         x = area->x + (w - mw) / 2;
151         break;
152     }
153
154     l = strlen(text->str); /* number of bytes */
155
156     if (t->shadow) {
157         if (t->tint >= 0) {
158             c.color.red = 0;
159             c.color.green = 0;
160             c.color.blue = 0;
161             c.color.alpha = 0xffff * t->tint / 100; /* transparent shadow */
162             c.pixel = BlackPixel(RrDisplay(t->font->inst),
163                                  RrScreen(t->font->inst));
164         } else {
165             c.color.red = 0xffff * -t->tint / 100;
166             c.color.green = 0xffff * -t->tint / 100;
167             c.color.blue = 0xffff * -t->tint / 100;
168             c.color.alpha = 0xffff * -t->tint / 100; /* transparent shadow */
169             c.pixel = WhitePixel(RrDisplay(t->font->inst),
170                                  RrScreen(t->font->inst));
171         }  
172         XftDrawStringUtf8(d, &c, t->font->xftfont, x + t->offset,
173                           t->font->xftfont->ascent + y + t->offset,
174                           (FcChar8*)text->str, l);
175     }  
176     c.color.red = t->color->r | t->color->r << 8;
177     c.color.green = t->color->g | t->color->g << 8;
178     c.color.blue = t->color->b | t->color->b << 8;
179     c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
180     c.pixel = t->color->pixel;
181                      
182     XftDrawStringUtf8(d, &c, t->font->xftfont, x,
183                       t->font->xftfont->ascent + y,
184                       (FcChar8*)text->str, l);
185     return;
186 }