windowmaker-wl/WINGs/wfont_x11.c

214 lines
6.3 KiB
C

/*
* wfont_x11.c — X11/Xft + PangoXft font backend for WINGs.
*
* Per-screen state (ScreenCtxX11): XftDraw + display + screen number.
* Per-font handle (FontHandleX11): XftFont* + PangoLayout*.
*/
#include "wconfig.h"
#include "WINGsP.h"
#include "WINGs/WINGsX11.h"
#include <X11/Xft/Xft.h>
#include <fontconfig/fontconfig.h>
#ifdef USE_PANGO
#include <pango/pangoxft.h>
#include <pango/pangofc-fontmap.h>
#endif
/* ------------------------------------------------------------------ */
typedef struct {
Display *display;
int screen_num;
XftDraw *xftdraw;
#ifdef USE_PANGO
PangoFontMap *fontmap;
#endif
} ScreenCtxX11;
typedef struct {
Display *display; /* needed for XftFontClose / XftTextExtentsUtf8 */
XftFont *xft;
#ifdef USE_PANGO
PangoLayout *layout;
#endif
} FontHandleX11;
/* ------------------------------------------------------------------ */
static void *
x11_screen_init(W_Screen *scr)
{
ScreenCtxX11 *ctx = wmalloc(sizeof(*ctx));
ctx->display = scr->display;
ctx->screen_num = scr->screen;
ctx->xftdraw = XftDrawCreate(scr->display,
W_DRAWABLE(scr),
scr->visual,
scr->colormap);
#ifdef USE_PANGO
ctx->fontmap = pango_xft_get_font_map(scr->display, scr->screen);
#endif
return ctx;
}
static void
x11_screen_fini(void *sctx)
{
ScreenCtxX11 *ctx = sctx;
XftDrawDestroy(ctx->xftdraw);
wfree(ctx);
}
static void *
x11_font_open(void *sctx, const char *fc_name, int *height_out, int *y_out)
{
ScreenCtxX11 *ctx = sctx;
FontHandleX11 *h = wmalloc(sizeof(*h));
h->display = ctx->display;
h->xft = XftFontOpenName(ctx->display, ctx->screen_num, fc_name);
if (!h->xft) {
wfree(h);
return NULL;
}
*height_out = h->xft->ascent + h->xft->descent;
*y_out = h->xft->ascent;
#ifdef USE_PANGO
{
PangoContext *pctx = pango_font_map_create_context(ctx->fontmap);
FcPattern *pat = FcNameParse((FcChar8 *)fc_name);
PangoFontDescription *desc = pango_fc_font_description_from_pattern(pat, FALSE);
double sz = 0;
h->layout = pango_layout_new(pctx);
if (FcPatternGetDouble(pat, FC_PIXEL_SIZE, 0, &sz) == FcResultMatch)
pango_font_description_set_absolute_size(desc, sz * PANGO_SCALE);
pango_layout_set_font_description(h->layout, desc);
pango_font_description_free(desc);
FcPatternDestroy(pat);
g_object_unref(pctx);
}
#endif
return h;
}
static void
x11_font_close(void *sctx, void *handle)
{
FontHandleX11 *h = handle;
(void)sctx;
if (!h) return;
#ifdef USE_PANGO
if (h->layout) g_object_unref(h->layout);
#endif
XftFontClose(h->display, h->xft);
wfree(h);
}
static int
x11_text_width(void *handle, const char *text, int len)
{
FontHandleX11 *h = handle;
#ifdef USE_PANGO
const char *prev = pango_layout_get_text(h->layout);
if (!prev || strncmp(text, prev, (size_t)len) != 0 || prev[len] != '\0')
pango_layout_set_text(h->layout, text, len);
int w = 0;
pango_layout_get_pixel_size(h->layout, &w, NULL);
return w;
#else
XGlyphInfo ext;
XftTextExtentsUtf8(h->display, h->xft, (XftChar8 *)text, len, &ext);
return ext.xOff;
#endif
}
static void
x11_draw_string(void *sctx, void *handle, WMDrawable d,
int x, int y,
unsigned short r, unsigned short g,
unsigned short b, unsigned short a,
unsigned long pixel,
const char *text, int len)
{
ScreenCtxX11 *ctx = sctx;
FontHandleX11 *h = handle;
XftColor xc = { .pixel = pixel,
.color = { .red=r, .green=g, .blue=b, .alpha=a } };
XftDrawChange(ctx->xftdraw, (Drawable)d);
#ifdef USE_PANGO
const char *prev = pango_layout_get_text(h->layout);
if (!prev || strcmp(text, prev) != 0)
pango_layout_set_text(h->layout, text, len);
pango_xft_render_layout(ctx->xftdraw, &xc, h->layout,
x * PANGO_SCALE, y * PANGO_SCALE);
#else
XftDrawStringUtf8(ctx->xftdraw, &xc, h->xft,
x, y + h->xft->ascent,
(XftChar8 *)text, len);
#endif
}
static void
x11_draw_image_string(void *sctx, void *handle, WMDrawable d,
int x, int y,
unsigned short tr, unsigned short tg,
unsigned short tb, unsigned short ta, unsigned long tpix,
unsigned short br, unsigned short bg,
unsigned short bb, unsigned short ba, unsigned long bpix,
int bg_w, int bg_h,
const char *text, int len)
{
ScreenCtxX11 *ctx = sctx;
FontHandleX11 *h = handle;
XftColor tc = { .pixel = tpix,
.color = { .red=tr, .green=tg, .blue=tb, .alpha=ta } };
XftColor bc = { .pixel = bpix,
.color = { .red=br, .green=bg, .blue=bb, .alpha=ba } };
XftDrawChange(ctx->xftdraw, (Drawable)d);
XftDrawRect(ctx->xftdraw, &bc, x, y, (unsigned)bg_w, (unsigned)bg_h);
#ifdef USE_PANGO
const char *prev = pango_layout_get_text(h->layout);
if (!prev || strcmp(text, prev) != 0)
pango_layout_set_text(h->layout, text, len);
pango_xft_render_layout(ctx->xftdraw, &tc, h->layout,
x * PANGO_SCALE, y * PANGO_SCALE);
#else
XftDrawStringUtf8(ctx->xftdraw, &tc, h->xft,
x, y + h->xft->ascent,
(XftChar8 *)text, len);
#endif
}
static int
x11_lookup_string(void *sctx, W_View *view, WMEvent *event,
char *buffer, int buflen, unsigned long *keysym_out)
{
(void)sctx;
if (!event->_x11_raw) { *keysym_out = 0; return 0; }
return W_LookupString(view, &((XEvent *)event->_x11_raw)->xkey,
buffer, buflen, (KeySym *)keysym_out, NULL);
}
const W_FontBackend W_FontBackendX11 = {
.screen_init = x11_screen_init,
.screen_fini = x11_screen_fini,
.font_open = x11_font_open,
.font_close = x11_font_close,
.text_width = x11_text_width,
.draw_string = x11_draw_string,
.draw_image_string = x11_draw_image_string,
.lookup_string = x11_lookup_string,
};