Use Xft for font loading and text drawing

This commit is contained in:
Bert Münnich 2016-08-06 15:27:58 +02:00
parent aabc2bddbd
commit c280129cef
8 changed files with 56 additions and 98 deletions

View file

@ -5,9 +5,9 @@ MANPREFIX := $(PREFIX)/share/man
CC ?= gcc CC ?= gcc
CFLAGS += -std=c99 -Wall -pedantic CFLAGS += -std=c99 -Wall -pedantic
CPPFLAGS += -I$(PREFIX)/include -D_XOPEN_SOURCE=700 CPPFLAGS += -I/usr/include/freetype2 -D_XOPEN_SOURCE=700
LDFLAGS += -L$(PREFIX)/lib LDFLAGS +=
LIBS := -lX11 -lImlib2 LIBS := -lImlib2 -lX11 -lXft
# optional dependencies: # optional dependencies:
# giflib: gif animations # giflib: gif animations

View file

@ -2,12 +2,11 @@
**Simple X Image Viewer** **Simple X Image Viewer**
sxiv is an alternative to feh and qiv. Its only dependencies besides xlib are The primary goal of sxiv is to create an image viewer, which only has the most
imlib2, libexif and giflib. The primary goal for writing sxiv is to create an basic features required for fast image viewing (the ones I want). It has vi key
image viewer, which only has the most basic features required for fast image bindings and works nicely with tiling window managers. Its code base should be
viewing (the ones I want). It has vi key bindings and works nicely with tiling kept small and clean to make it easy for you to dig into it and customize it
window managers. Its code base should be kept small and clean to make it easy for your needs.
for you to dig into it and customize it for your needs.
Features Features

View file

@ -7,9 +7,9 @@ enum {
}; };
/* bar font: /* bar font:
* (see X(7) section "FONT NAMES" for valid values) * (see fonts-conf(5) subsection "FONT NAMES" for valid values)
*/ */
static const char * const BAR_FONT = "-*-fixed-medium-r-*-*-13-*-*-*-*-60-*-*"; static const char * const BAR_FONT = "monospace:size=8";
/* colors: /* colors:
* (see X(7) section "COLOR NAMES" for valid values) * (see X(7) section "COLOR NAMES" for valid values)

View file

@ -485,7 +485,7 @@ void img_render(img_t *img)
} }
imlib_image_put_back_data(data); imlib_image_put_back_data(data);
} else { } else {
c = win->fullscreen ? win->fscol : win->bgcol; c = win->fullscreen ? win->fscol.pixel : win->bgcol.pixel;
imlib_context_set_color(c >> 16 & 0xFF, c >> 8 & 0xFF, c & 0xFF, 0xFF); imlib_context_set_color(c >> 16 & 0xFF, c >> 8 & 0xFF, c & 0xFF, 0xFF);
imlib_image_fill_rectangle(0, 0, dw, dh); imlib_image_fill_rectangle(0, 0, dw, dh);
} }

4
main.c
View file

@ -386,8 +386,8 @@ void update_info(void)
if (ow_info) { if (ow_info) {
fn = strlen(files[fileidx].name); fn = strlen(files[fileidx].name);
if (fn < l->size && if (fn < l->size &&
win_textwidth(files[fileidx].name, fn, true) + win_textwidth(&win.env, files[fileidx].name, fn, true) +
win_textwidth(r->buf, r->p - r->buf, true) < win.w) win_textwidth(&win.env, r->buf, r->p - r->buf, true) < win.w)
{ {
strncpy(l->buf, files[fileidx].name, l->size); strncpy(l->buf, files[fileidx].name, l->size);
} else { } else {

View file

@ -480,14 +480,14 @@ void tns_mark(tns_t *tns, int n, bool mark)
if (n >= 0 && n < *tns->cnt && tns->thumbs[n].im != NULL) { if (n >= 0 && n < *tns->cnt && tns->thumbs[n].im != NULL) {
win_t *win = tns->win; win_t *win = tns->win;
thumb_t *t = &tns->thumbs[n]; thumb_t *t = &tns->thumbs[n];
unsigned long col = win->fullscreen ? win->fscol : win->bgcol; unsigned long col = win->fullscreen ? win->fscol.pixel : win->bgcol.pixel;
int x = t->x + t->w, y = t->y + t->h; int x = t->x + t->w, y = t->y + t->h;
win_draw_rect(win, x - 1, y + 1, 1, tns->bw, true, 1, col); win_draw_rect(win, x - 1, y + 1, 1, tns->bw, true, 1, col);
win_draw_rect(win, x + 1, y - 1, tns->bw, 1, true, 1, col); win_draw_rect(win, x + 1, y - 1, tns->bw, 1, true, 1, col);
if (mark) if (mark)
col = win->selcol; col = win->selcol.pixel;
win_draw_rect(win, x, y, tns->bw + 2, tns->bw + 2, true, 1, col); win_draw_rect(win, x, y, tns->bw + 2, tns->bw + 2, true, 1, col);
@ -505,9 +505,9 @@ void tns_highlight(tns_t *tns, int n, bool hl)
int oxy = (tns->bw + 1) / 2 + 1, owh = tns->bw + 2; int oxy = (tns->bw + 1) / 2 + 1, owh = tns->bw + 2;
if (hl) if (hl)
col = win->selcol; col = win->selcol.pixel;
else else
col = win->fullscreen ? win->fscol : win->bgcol; col = win->fullscreen ? win->fscol.pixel : win->bgcol.pixel;
win_draw_rect(win, t->x - oxy, t->y - oxy, t->w + owh, t->h + owh, win_draw_rect(win, t->x - oxy, t->y - oxy, t->w + owh, t->h + owh,
false, tns->bw, col); false, tns->bw, col);

106
window.c
View file

@ -41,13 +41,7 @@ static Cursor chand;
static Cursor cwatch; static Cursor cwatch;
static GC gc; static GC gc;
static struct { static XftFont *font;
int ascent;
int descent;
XFontStruct *xfont;
XFontSet set;
} font;
static int fontheight; static int fontheight;
static int barheight; static int barheight;
@ -56,50 +50,21 @@ Atom atoms[ATOM_COUNT];
static Bool fs_support; static Bool fs_support;
static Bool fs_warned; static Bool fs_warned;
void win_init_font(Display *dpy, const char *fontstr) void win_init_font(const win_env_t *e, const char *fontstr)
{ {
int n; if ((font = XftFontOpenName(e->dpy, e->scr, fontstr)) == NULL)
char *def, **missing; error(EXIT_FAILURE, 0, "Error loading font '%s'", fontstr);
fontheight = font->ascent + font->descent;
font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
if (missing)
XFreeStringList(missing);
if (font.set) {
XFontStruct **xfonts;
char **font_names;
font.ascent = font.descent = 0;
XExtentsOfFontSet(font.set);
n = XFontsOfFontSet(font.set, &xfonts, &font_names);
while (n--) {
font.ascent = MAX(font.ascent, (*xfonts)->ascent);
font.descent = MAX(font.descent,(*xfonts)->descent);
xfonts++;
}
} else {
if ((font.xfont = XLoadQueryFont(dpy, fontstr)) == NULL &&
(font.xfont = XLoadQueryFont(dpy, "fixed")) == NULL)
{
error(EXIT_FAILURE, 0, "Error loading font '%s'", fontstr);
}
font.ascent = font.xfont->ascent;
font.descent = font.xfont->descent;
}
fontheight = font.ascent + font.descent;
barheight = fontheight + 2 * V_TEXT_PAD; barheight = fontheight + 2 * V_TEXT_PAD;
} }
unsigned long win_alloc_color(win_t *win, const char *name) void win_alloc_color(const win_env_t *e, const char *name, XftColor *col)
{ {
XColor col; if (!XftColorAllocName(e->dpy, DefaultVisual(e->dpy, e->scr),
DefaultColormap(e->dpy, e->scr), name, col))
if (XAllocNamedColor(win->env.dpy,
DefaultColormap(win->env.dpy, win->env.scr),
name, &col, &col) == 0)
{ {
error(EXIT_FAILURE, 0, "Error allocating color '%s'", name); error(EXIT_FAILURE, 0, "Error allocating color '%s'", name);
} }
return col.pixel;
} }
void win_check_wm_support(Display *dpy, Window root) void win_check_wm_support(Display *dpy, Window root)
@ -155,13 +120,13 @@ void win_init(win_t *win)
if (setlocale(LC_CTYPE, "") == NULL || XSupportsLocale() == 0) if (setlocale(LC_CTYPE, "") == NULL || XSupportsLocale() == 0)
error(0, 0, "No locale support"); error(0, 0, "No locale support");
win_init_font(e->dpy, BAR_FONT); win_init_font(e, BAR_FONT);
win->bgcol = win_alloc_color(win, WIN_BG_COLOR); win_alloc_color(e, WIN_BG_COLOR, &win->bgcol);
win->fscol = win_alloc_color(win, WIN_FS_COLOR); win_alloc_color(e, WIN_FS_COLOR, &win->fscol);
win->selcol = win_alloc_color(win, SEL_COLOR); win_alloc_color(e, SEL_COLOR, &win->selcol);
win->bar.bgcol = win_alloc_color(win, BAR_BG_COLOR); win_alloc_color(e, BAR_BG_COLOR, &win->bar.bgcol);
win->bar.fgcol = win_alloc_color(win, BAR_FG_COLOR); win_alloc_color(e, BAR_FG_COLOR, &win->bar.fgcol);
win->bar.l.size = BAR_L_LEN; win->bar.l.size = BAR_L_LEN;
win->bar.r.size = BAR_R_LEN; win->bar.r.size = BAR_R_LEN;
@ -295,7 +260,7 @@ void win_open(win_t *win)
win->buf.h = e->scrh; win->buf.h = e->scrh;
win->buf.pm = XCreatePixmap(e->dpy, win->xwin, win->buf.pm = XCreatePixmap(e->dpy, win->xwin,
win->buf.w, win->buf.h, e->depth); win->buf.w, win->buf.h, e->depth);
XSetForeground(e->dpy, gc, fullscreen ? win->fscol : win->bgcol); XSetForeground(e->dpy, gc, fullscreen ? win->fscol.pixel : win->bgcol.pixel);
XFillRectangle(e->dpy, win->buf.pm, gc, 0, 0, win->buf.w, win->buf.h); XFillRectangle(e->dpy, win->buf.pm, gc, 0, 0, win->buf.w, win->buf.h);
XSetWindowBackgroundPixmap(e->dpy, win->xwin, win->buf.pm); XSetWindowBackgroundPixmap(e->dpy, win->xwin, win->buf.pm);
@ -387,7 +352,7 @@ void win_clear(win_t *win)
win->buf.pm = XCreatePixmap(e->dpy, win->xwin, win->buf.pm = XCreatePixmap(e->dpy, win->xwin,
win->buf.w, win->buf.h, e->depth); win->buf.w, win->buf.h, e->depth);
} }
XSetForeground(e->dpy, gc, win->fullscreen ? win->fscol : win->bgcol); XSetForeground(e->dpy, gc, win->fullscreen ? win->fscol.pixel : win->bgcol.pixel);
XFillRectangle(e->dpy, win->buf.pm, gc, 0, 0, win->buf.w, win->buf.h); XFillRectangle(e->dpy, win->buf.pm, gc, 0, 0, win->buf.w, win->buf.h);
} }
@ -398,33 +363,33 @@ void win_draw_bar(win_t *win)
const char *dots = "..."; const char *dots = "...";
win_env_t *e; win_env_t *e;
win_bar_t *l, *r; win_bar_t *l, *r;
XftDraw *d;
if ((l = &win->bar.l)->buf == NULL || (r = &win->bar.r)->buf == NULL) if ((l = &win->bar.l)->buf == NULL || (r = &win->bar.r)->buf == NULL)
return; return;
e = &win->env; e = &win->env;
y = win->h + font.ascent + V_TEXT_PAD; y = win->h + font->ascent + V_TEXT_PAD;
w = win->w; w = win->w;
d = XftDrawCreate(e->dpy, win->buf.pm, DefaultVisual(e->dpy, e->scr),
DefaultColormap(e->dpy, e->scr));
XSetForeground(e->dpy, gc, win->bar.bgcol); XSetForeground(e->dpy, gc, win->bar.bgcol.pixel);
XFillRectangle(e->dpy, win->buf.pm, gc, 0, win->h, win->w, win->bar.h); XFillRectangle(e->dpy, win->buf.pm, gc, 0, win->h, win->w, win->bar.h);
XSetForeground(e->dpy, gc, win->bar.fgcol); XSetForeground(e->dpy, gc, win->bar.fgcol.pixel);
XSetBackground(e->dpy, gc, win->bar.bgcol); XSetBackground(e->dpy, gc, win->bar.bgcol.pixel);
if ((len = strlen(r->buf)) > 0) { if ((len = strlen(r->buf)) > 0) {
if ((tw = win_textwidth(r->buf, len, true)) > w) if ((tw = win_textwidth(e, r->buf, len, true)) > w)
return; return;
x = win->w - tw + H_TEXT_PAD; x = win->w - tw + H_TEXT_PAD;
w -= tw; w -= tw;
if (font.set) XftDrawStringUtf8(d, &win->bar.fgcol, font, x, y, (XftChar8*)r->buf, len);
XmbDrawString(e->dpy, win->buf.pm, font.set, gc, x, y, r->buf, len);
else
XDrawString(e->dpy, win->buf.pm, gc, x, y, r->buf, len);
} }
if ((len = strlen(l->buf)) > 0) { if ((len = strlen(l->buf)) > 0) {
olen = len; olen = len;
while (len > 0 && (tw = win_textwidth(l->buf, len, true)) > w) while (len > 0 && (tw = win_textwidth(e, l->buf, len, true)) > w)
len--; len--;
if (len > 0) { if (len > 0) {
if (len != olen) { if (len != olen) {
@ -435,14 +400,12 @@ void win_draw_bar(win_t *win)
memcpy(l->buf + len - w, dots, w); memcpy(l->buf + len - w, dots, w);
} }
x = H_TEXT_PAD; x = H_TEXT_PAD;
if (font.set) XftDrawStringUtf8(d, &win->bar.fgcol, font, x, y, (XftChar8*)l->buf, len);
XmbDrawString(e->dpy, win->buf.pm, font.set, gc, x, y, l->buf, len);
else
XDrawString(e->dpy, win->buf.pm, gc, x, y, l->buf, len);
if (len != olen) if (len != olen)
memcpy(l->buf + len - w, rest, w); memcpy(l->buf + len - w, rest, w);
} }
} }
XftDrawDestroy(d);
} }
void win_draw(win_t *win) void win_draw(win_t *win)
@ -470,17 +433,12 @@ void win_draw_rect(win_t *win, int x, int y, int w, int h, bool fill, int lw,
XDrawRectangle(win->env.dpy, win->buf.pm, gc, x, y, w, h); XDrawRectangle(win->env.dpy, win->buf.pm, gc, x, y, w, h);
} }
int win_textwidth(const char *text, unsigned int len, bool with_padding) int win_textwidth(const win_env_t *e, const char *text, unsigned int len, bool with_padding)
{ {
XRectangle r; XGlyphInfo ext;
int padding = with_padding ? 2 * H_TEXT_PAD : 0;
if (font.set) { XftTextExtentsUtf8(e->dpy, font, (XftChar8*)text, len, &ext);
XmbTextExtents(font.set, text, len, NULL, &r); return ext.xOff + (with_padding ? 2 * H_TEXT_PAD : 0);
return r.width + padding;
} else {
return XTextWidth(font.xfont, text, len) + padding;
}
} }
void win_set_title(win_t *win, const char *title) void win_set_title(win_t *win, const char *title)

View file

@ -21,6 +21,7 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/Xft/Xft.h>
#include "types.h" #include "types.h"
@ -59,9 +60,9 @@ typedef struct {
Window xwin; Window xwin;
win_env_t env; win_env_t env;
unsigned long bgcol; XftColor bgcol;
unsigned long fscol; XftColor fscol;
unsigned long selcol; XftColor selcol;
int x; int x;
int y; int y;
@ -81,8 +82,8 @@ typedef struct {
unsigned int h; unsigned int h;
win_bar_t l; win_bar_t l;
win_bar_t r; win_bar_t r;
unsigned long bgcol; XftColor bgcol;
unsigned long fgcol; XftColor fgcol;
} bar; } bar;
} win_t; } win_t;
@ -101,7 +102,7 @@ void win_clear(win_t*);
void win_draw(win_t*); void win_draw(win_t*);
void win_draw_rect(win_t*, int, int, int, int, bool, int, unsigned long); void win_draw_rect(win_t*, int, int, int, int, bool, int, unsigned long);
int win_textwidth(const char*, unsigned int, bool); int win_textwidth(const win_env_t*, const char*, unsigned int, bool);
void win_set_title(win_t*, const char*); void win_set_title(win_t*, const char*);
void win_set_cursor(win_t*, cursor_t); void win_set_cursor(win_t*, cursor_t);