Add Xft support.

This commit is contained in:
Kris Maglione 2009-05-21 13:55:34 -04:00
parent 3dd6ee6658
commit 65f7040f2c
3 changed files with 133 additions and 45 deletions

View File

@ -26,6 +26,8 @@ static MapEnt* abucket[137];
static int errorhandler(Display*, XErrorEvent*);
static int (*xlib_errorhandler) (Display*, XErrorEvent*);
static XftColor* xftcolor(ulong);
/* Rectangles/Points */
XRectangle
@ -249,11 +251,20 @@ freeimage(Image *img) {
assert(img->type == WImage);
if(img->xft)
XftDrawDestroy(img->xft);
XFreePixmap(display, img->w);
XFreeGC(display, img->gc);
free(img);
}
static XftDraw*
xftdrawable(Image *img) {
if(img->xft == nil)
img->xft = XftDrawCreate(display, img->w, scr.visual, scr.colormap);
return img->xft;
}
/* Windows */
Window*
createwindow_visual(Window *parent, Rectangle r,
@ -309,6 +320,8 @@ void
destroywindow(Window *w) {
assert(w->type == WWindow);
sethandler(w, nil);
if(w->xft)
XftDrawDestroy(w->xft);
if(w->gc)
XFreeGC(display, w->gc);
XDestroyWindow(display, w->w);
@ -561,16 +574,25 @@ drawstring(Image *dst, Font *font,
}
setgccol(dst, col);
if(font->set)
switch(font->type) {
case FFontSet:
Xutf8DrawString(display, dst->w,
font->set, dst->gc,
font->font.set, dst->gc,
x, y,
buf, len);
else {
XSetFont(display, dst->gc, font->xfont->fid);
break;
case FXft:
XftDrawStringUtf8(xftdrawable(dst), xftcolor(col),
font->font.xft,
x, y, (uchar*)buf, len);
break;
case FX11:
XSetFont(display, dst->gc, font->font.x11->fid);
XDrawString(display, dst->w, dst->gc,
x, y,
buf, len);
x, y, buf, len);
break;
default:
die("Invalid font type.");
}
done:
@ -617,55 +639,98 @@ loadcolor(CTuple *c, char *str) {
&& namedcolor(buf+16, &c->border);
}
static XftColor*
xftcolor(ulong col) {
XftColor *c;
c = emallocz(sizeof *c);
*c = (XftColor) {
col, {
(col>>8) & 0xff00,
(col>>0) & 0xff00,
(col<<8) & 0xff00,
(col>>16) & 0xff00,
}
};
return freelater(c);
}
/* Fonts */
Font*
loadfont(char *name) {
Biobuf *b;
Font *f;
XFontStruct **xfonts;
char **missing, **font_names;
Biobuf *b;
Font *f;
int n, i;
missing = nil;
f = emallocz(sizeof *f);
f->name = estrdup(name);
f->set = XCreateFontSet(display, name, &missing, &n, nil);
if(missing) {
b = Bfdopen(dup(2), O_WRONLY);
Bprint(b, "%s: note: missing fontset%s for '%s':", argv0,
(n > 1 ? "s" : ""), name);
for(i = 0; i < n; i++)
Bprint(b, "%s %s", (i ? "," : ""), missing[i]);
Bprint(b, "\n");
Bterm(b);
freestringlist(missing);
}
if(!strncmp(f->name, "xft:", 4)) {
f->type = FXft;
if(f->set) {
XFontsOfFontSet(f->set, &xfonts, &font_names);
f->ascent = xfonts[0]->ascent;
f->descent = xfonts[0]->descent;
f->font.xft = XftFontOpenXlfd(display, scr.screen, f->name + 4);
if(!f->font.xft)
f->font.xft = XftFontOpenName(display, scr.screen, f->name + 4);
if(!f->font.xft)
goto error;
f->ascent = f->font.xft->ascent;
f->descent = f->font.xft->descent;
}else {
f->xfont = XLoadQueryFont(display, name);
if(!f->xfont) {
fprint(2, "%s: cannot load font: %s\n", argv0, name);
freefont(f);
return nil;
f->font.set = XCreateFontSet(display, name, &missing, &n, nil);
if(missing) {
b = Bfdopen(dup(2), O_WRONLY);
Bprint(b, "%s: note: missing fontset%s for '%s':", argv0,
(n > 1 ? "s" : ""), name);
for(i = 0; i < n; i++)
Bprint(b, "%s %s", (i ? "," : ""), missing[i]);
Bprint(b, "\n");
Bterm(b);
freestringlist(missing);
}
f->ascent = f->xfont->ascent;
f->descent = f->xfont->descent;
if(f->font.set) {
f->type = FFontSet;
XFontsOfFontSet(f->font.set, &xfonts, &font_names);
f->ascent = xfonts[0]->ascent;
f->descent = xfonts[0]->descent;
}else {
f->type = FX11;
f->font.x11 = XLoadQueryFont(display, name);
if(!f->font.x11)
goto error;
f->ascent = f->font.x11->ascent;
f->descent = f->font.x11->descent;
}
}
f->height = f->ascent + f->descent;
return f;
error:
fprint(2, "%s: cannot load font: %s\n", argv0, name);
f->type = 0;
freefont(f);
return nil;
}
void
freefont(Font *f) {
if(f->set)
XFreeFontSet(display, f->set);
if(f->xfont)
XFreeFont(display, f->xfont);
switch(f->type) {
case FFontSet:
XFreeFontSet(display, f->font.set);
break;
case FXft:
XftFontClose(display, f->font.xft);
break;
case FX11:
XFreeFont(display, f->font.x11);
break;
default:
break;
}
free(f->name);
free(f);
}
@ -673,12 +738,21 @@ freefont(Font *f) {
uint
textwidth_l(Font *font, char *text, uint len) {
XRectangle r;
XGlyphInfo i;
if(font->set) {
Xutf8TextExtents(font->set, text, len, nil, &r);
switch(font->type) {
case FFontSet:
Xutf8TextExtents(font->font.set, text, len, nil, &r);
return r.width;
case FXft:
XftTextExtentsUtf8(display, font->font.xft, (uchar*)text, len, &i);
return i.width;
case FX11:
return XTextWidth(font->font.x11, text, len);
default:
die("Invalid font type");
return 0; /* shut up ken */
}
return XTextWidth(font->xfont, text, len);
}
uint

View File

@ -33,8 +33,8 @@ P9PATHS = ${PLAN9}:"'$${HOME}/plan9'":/usr/local/plan9:/usr/local/9:/opt/plan9:/
# are painfully slow, and should be avoided.
#BINSH = /bin/ash
INCX11 = -I/usr/X11R6/include
LIBX11 = -L/usr/X11R6/lib -lX11
INCX11 = $$(pkg-config --cflags xft)
LIBX11 = $$(pkg-config --libs xft)
LIBICONV = # Leave blank if your libc includes iconv (glibc does)
LIBIXP = $(LIBDIR)/libixp.a

View File

@ -6,6 +6,7 @@
#define Screen XScreen
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xft/Xft.h>
#ifdef _X11_VISIBLE
# include <X11/Xatom.h>
# include <X11/extensions/shape.h>
@ -27,12 +28,20 @@ enum Align {
Center = NEast | SWest,
};
enum FontType {
FX11 = 1,
FFontSet,
FXft,
};
enum WindowType {
WWindow,
WImage,
};
typedef enum Align Align;
typedef enum FontType FontType;
typedef enum WindowType WindowType;
typedef XSetWindowAttributes WinAttr;
@ -76,12 +85,16 @@ struct Ewmh {
};
struct Font {
XFontStruct *xfont;
XFontSet set;
int ascent;
int descent;
uint height;
char *name;
int type;
union {
XFontStruct* x11;
XFontSet set;
XftFont* xft;
} font;
int ascent;
int descent;
uint height;
char* name;
};
struct Handlers {
@ -122,6 +135,7 @@ struct Window {
int type;
XID w;
GC gc;
XftDraw* xft;
Rectangle r;
int border;
Window* parent;