/* * 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 #include #ifdef USE_PANGO #include #include #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, };