From c280129cef4ff2e8667b8700c9bdf671fdd7c8ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bert=20M=C3=BCnnich?= Date: Sat, 6 Aug 2016 15:27:58 +0200 Subject: [PATCH] Use Xft for font loading and text drawing --- Makefile | 6 +-- README.md | 11 +++--- config.def.h | 4 +- image.c | 2 +- main.c | 4 +- thumbs.c | 8 ++-- window.c | 106 ++++++++++++++++----------------------------------- window.h | 13 ++++--- 8 files changed, 56 insertions(+), 98 deletions(-) diff --git a/Makefile b/Makefile index 2c39905..fc75c00 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README.md b/README.md index dfb29b8..28334b0 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/config.def.h b/config.def.h index f3cc71e..bfa1338 100644 --- a/config.def.h +++ b/config.def.h @@ -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) diff --git a/image.c b/image.c index 9350ab1..ebd522d 100644 --- a/image.c +++ b/image.c @@ -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); } diff --git a/main.c b/main.c index 361477e..5b41170 100644 --- a/main.c +++ b/main.c @@ -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 { diff --git a/thumbs.c b/thumbs.c index bfce2ff..f51f85f 100644 --- a/thumbs.c +++ b/thumbs.c @@ -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); diff --git a/window.c b/window.c index 696c2ea..ad08787 100644 --- a/window.c +++ b/window.c @@ -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) - { - error(EXIT_FAILURE, 0, "Error loading font '%s'", fontstr); - } - font.ascent = font.xfont->ascent; - font.descent = font.xfont->descent; - } - fontheight = font.ascent + font.descent; + if ((font = XftFontOpenName(e->dpy, e->scr, fontstr)) == NULL) + error(EXIT_FAILURE, 0, "Error loading font '%s'", fontstr); + 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) diff --git a/window.h b/window.h index 31bd898..f5f9df0 100644 --- a/window.h +++ b/window.h @@ -21,6 +21,7 @@ #include #include +#include #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);