aboutsummaryrefslogtreecommitdiff
path: root/xft.go
blob: d1e4e8521f26a14f2eb8afb3ae0258efc64b9b68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main

/*
#cgo pkg-config: xft xrender x11 fontconfig
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
#include <X11/Xft/Xft.h>

static Display *_dpy;
static XftDraw *_drw;
static XftFont *_ft;
static Visual *_vis;
static Colormap _cmap;
static XftColor _fg;
static int _scr;

static int wm_xft_init(const char *pattern)
{
    int event_basep, error_basep;
    _dpy = XOpenDisplay(NULL);
    if (!_dpy)
        return -1;
    if (!XRenderQueryExtension(_dpy, &event_basep, &error_basep))
        return -3;
    XftInit(NULL);
    _scr = DefaultScreen(_dpy);
    _vis = DefaultVisual(_dpy, _scr);
    _cmap = DefaultColormap(_dpy, _scr);
    _ft = XftFontOpenName(_dpy, _scr, pattern);
    if (!_ft)
        return -2;
    return 0;
}

static void wm_xft_setfg(unsigned int px)
{
    XRenderColor c;
    c.red   = ((px >> 16) & 0xff) << 8;
    c.green = ((px >> 8) & 0xff) << 8;
    c.blue  = (px & 0xff) << 8;
    c.alpha = 0xffff;
    XftColorAllocValue(_dpy, _vis, _cmap, &c, &_fg);
}

static int wm_xft_width(const char *s, int n)
{
    XGlyphInfo gi;
    XftTextExtentsUtf8(_dpy, _ft, (const FcChar8 *)s, n, &gi);
    return gi.xOff;
}

static void wm_xft_draw(unsigned int win, int x, int y,
                        const char *s, int n, unsigned int fg)
{
    if (!_dpy || !_ft || !win)
        return;
    if (!_drw)
        _drw = XftDrawCreate(_dpy, (Drawable)win, _vis, _cmap);
    if (!_drw)
        return;
    XftDrawChange(_drw, (Drawable)win);
    wm_xft_setfg(fg);
    XftDrawStringUtf8(_drw, &_fg, _ft, x, y, (const FcChar8 *)s, n);
    XSync(_dpy, False);
}

static int wm_xft_ascent(void)  { return _ft ? _ft->ascent : 0; }
static int wm_xft_descent(void) { return _ft ? _ft->descent : 0; }
*/
import "C"

import (
	"unsafe"

	"github.com/BurntSushi/xgb/xproto"
)

var xftOK bool

func xftInit(pattern string) error {
	cp := C.CString(pattern)
	defer C.free(unsafe.Pointer(cp))

	switch rc := int(C.wm_xft_init(cp)); rc {
	case 0:
		xftOK = true
		return nil
	case -1:
		return errXftNoDisplay
	case -2:
		return errXftNoFont
	default:
		return errXftNoRender
	}
}

var (
	errXftNoDisplay = errXft("xft: cannot open display")
	errXftNoFont    = errXft("xft: cannot load font pattern")
	errXftNoRender  = errXft("xft: no RENDER extension")
)

type errXft string

func (e errXft) Error() string { return string(e) }

func xftTextWidth(s string) int {
	if !xftOK {
		return 0
	}
	cs := C.CString(s)
	defer C.free(unsafe.Pointer(cs))
	return int(C.wm_xft_width(cs, C.int(len(s))))
}

func xftDrawText(win xproto.Window, x, baseline int, s string, fg uint32) {
	if !xftOK || win == 0 {
		return
	}
	cs := C.CString(s)
	defer C.free(unsafe.Pointer(cs))
	C.wm_xft_draw(C.uint(win), C.int(x), C.int(baseline), cs, C.int(len(s)), C.uint(fg))
}

func xftMetrics() (ascent, descent int) {
	if !xftOK {
		return 0, 0
	}
	return int(C.wm_xft_ascent()), int(C.wm_xft_descent())
}