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
CFLAGS += -std=c99 -Wall -pedantic
CPPFLAGS += -I$(PREFIX)/include -D_XOPEN_SOURCE=700
LDFLAGS += -L$(PREFIX)/lib
LIBS := -lX11 -lImlib2
CPPFLAGS += -I/usr/include/freetype2 -D_XOPEN_SOURCE=700
LDFLAGS +=
LIBS := -lImlib2 -lX11 -lXft
# optional dependencies:
# giflib: gif animations

View file

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

View file

@ -7,9 +7,9 @@ enum {
};
/* 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:
* (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);
} 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_image_fill_rectangle(0, 0, dw, dh);
}

4
main.c
View file

@ -386,8 +386,8 @@ void update_info(void)
if (ow_info) {
fn = strlen(files[fileidx].name);
if (fn < l->size &&
win_textwidth(files[fileidx].name, fn, true) +
win_textwidth(r->buf, r->p - r->buf, true) < win.w)
win_textwidth(&win.env, files[fileidx].name, fn, true) +
win_textwidth(&win.env, r->buf, r->p - r->buf, true) < win.w)
{
strncpy(l->buf, files[fileidx].name, l->size);
} 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) {
win_t *win = tns->win;
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;
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);
if (mark)
col = win->selcol;
col = win->selcol.pixel;
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;
if (hl)
col = win->selcol;
col = win->selcol.pixel;
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,
false, tns->bw, col);

104
window.c
View file

@ -41,13 +41,7 @@ static Cursor chand;
static Cursor cwatch;
static GC gc;
static struct {
int ascent;
int descent;
XFontStruct *xfont;
XFontSet set;
} font;
static XftFont *font;
static int fontheight;
static int barheight;
@ -56,50 +50,21 @@ Atom atoms[ATOM_COUNT];
static Bool fs_support;
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;
char *def, **missing;
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)
{
if ((font = XftFontOpenName(e->dpy, e->scr, fontstr)) == 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;
fontheight = font->ascent + font->descent;
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 (XAllocNamedColor(win->env.dpy,
DefaultColormap(win->env.dpy, win->env.scr),
name, &col, &col) == 0)
if (!XftColorAllocName(e->dpy, DefaultVisual(e->dpy, e->scr),
DefaultColormap(e->dpy, e->scr), name, col))
{
error(EXIT_FAILURE, 0, "Error allocating color '%s'", name);
}
return col.pixel;
}
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)
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->fscol = win_alloc_color(win, WIN_FS_COLOR);
win->selcol = win_alloc_color(win, SEL_COLOR);
win->bar.bgcol = win_alloc_color(win, BAR_BG_COLOR);
win->bar.fgcol = win_alloc_color(win, BAR_FG_COLOR);
win_alloc_color(e, WIN_BG_COLOR, &win->bgcol);
win_alloc_color(e, WIN_FS_COLOR, &win->fscol);
win_alloc_color(e, SEL_COLOR, &win->selcol);
win_alloc_color(e, BAR_BG_COLOR, &win->bar.bgcol);
win_alloc_color(e, BAR_FG_COLOR, &win->bar.fgcol);
win->bar.l.size = BAR_L_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.pm = XCreatePixmap(e->dpy, win->xwin,
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);
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.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);
}
@ -398,33 +363,33 @@ void win_draw_bar(win_t *win)
const char *dots = "...";
win_env_t *e;
win_bar_t *l, *r;
XftDraw *d;
if ((l = &win->bar.l)->buf == NULL || (r = &win->bar.r)->buf == NULL)
return;
e = &win->env;
y = win->h + font.ascent + V_TEXT_PAD;
y = win->h + font->ascent + V_TEXT_PAD;
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);
XSetForeground(e->dpy, gc, win->bar.fgcol);
XSetBackground(e->dpy, gc, win->bar.bgcol);
XSetForeground(e->dpy, gc, win->bar.fgcol.pixel);
XSetBackground(e->dpy, gc, win->bar.bgcol.pixel);
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;
x = win->w - tw + H_TEXT_PAD;
w -= tw;
if (font.set)
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);
XftDrawStringUtf8(d, &win->bar.fgcol, font, x, y, (XftChar8*)r->buf, len);
}
if ((len = strlen(l->buf)) > 0) {
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--;
if (len > 0) {
if (len != olen) {
@ -435,14 +400,12 @@ void win_draw_bar(win_t *win)
memcpy(l->buf + len - w, dots, w);
}
x = H_TEXT_PAD;
if (font.set)
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);
XftDrawStringUtf8(d, &win->bar.fgcol, font, x, y, (XftChar8*)l->buf, len);
if (len != olen)
memcpy(l->buf + len - w, rest, w);
}
}
XftDrawDestroy(d);
}
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);
}
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;
int padding = with_padding ? 2 * H_TEXT_PAD : 0;
XGlyphInfo ext;
if (font.set) {
XmbTextExtents(font.set, text, len, NULL, &r);
return r.width + padding;
} else {
return XTextWidth(font.xfont, text, len) + padding;
}
XftTextExtentsUtf8(e->dpy, font, (XftChar8*)text, len, &ext);
return ext.xOff + (with_padding ? 2 * H_TEXT_PAD : 0);
}
void win_set_title(win_t *win, const char *title)

View file

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