Use Xft for font loading and text drawing
This commit is contained in:
parent
aabc2bddbd
commit
c280129cef
6
Makefile
6
Makefile
|
@ -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
|
||||||
|
|
11
README.md
11
README.md
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
2
image.c
2
image.c
|
@ -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
4
main.c
|
@ -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 {
|
||||||
|
|
8
thumbs.c
8
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) {
|
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);
|
||||||
|
|
104
window.c
104
window.c
|
@ -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;
|
|
||||||
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);
|
error(EXIT_FAILURE, 0, "Error loading font '%s'", fontstr);
|
||||||
}
|
fontheight = font->ascent + font->descent;
|
||||||
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)
|
||||||
|
|
13
window.h
13
window.h
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue