Below I discuss my monkeypatch for nsxiv.
I use media-gfx/nsxiv because...
My specific use case: I like having the entire background transparent, i.e. the image simply floats. Therefore I use this patch ⇗, with a small edit added, from nsxiv-extra.
Why would I want to add extra machinery when I can just poke the patch slightly? See the "edited by swomf" marker below.
/etc/portage/package.use/nsxiv
media-gfx/nsxiv exif savedconfig
/etc/portage/patches/media-gfx/nsxiv/alpha-275ec0d59.diff
diff --git a/image.c b/image.c
index 4e0cb21..c3a3c43 100644
--- a/image.c
+++ b/image.c
@@ -417,7 +417,6 @@ void img_render(img_t *img)
win_t *win;
int sx, sy, sw, sh;
int dx, dy, dw, dh;
- Imlib_Image bg;
win = img->win;
img_fit(img);
@@ -463,21 +462,45 @@ void img_render(img_t *img)
imlib_context_set_anti_alias(img->anti_alias);
imlib_context_set_drawable(win->buf.pm);
- /* manual blending, for performance reasons.
- * see https://phab.enlightenment.org/T8969#156167 for more details.
- */
+ render_core(win, sx, sy, sw, sh, dx, dy, dw, dh, img->alpha_layer);
+ img->dirty = false;
+}
+
+bool img_fit_win(img_t *img, scalemode_t sm)
+{
+ float oz;
+
+ oz = img->zoom;
+ img->scalemode = sm;
+
+ if (img_fit(img)) {
+ img->x = img->win->w / 2 - (img->win->w / 2 - img->x) * img->zoom / oz;
+ img->y = img->win->h / 2 - (img->win->h / 2 - img->y) * img->zoom / oz;
+ img->checkpan = true;
+ return true;
+ } else {
+ return false;
+ }
+}
+void render_core(win_t* win, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh,
+ bool alpha)
+{
+ Imlib_Image im, bg, bbg;
+ Imlib_Color_Modifier cmod;
+ XColor c;
+
if (imlib_image_has_alpha()) {
- if ((bg = imlib_create_image(dw, dh)) == NULL) {
- error(0, ENOMEM, "Failed to create image");
- goto fallback;
- }
+ im = imlib_context_get_image();
+ cmod = imlib_context_get_color_modifier();
+ if ((bg = imlib_create_image(dw, dh)) == NULL)
+ error(EXIT_FAILURE, ENOMEM, NULL);
imlib_context_set_image(bg);
- imlib_image_set_has_alpha(0);
+ imlib_image_set_has_alpha(1);
- if (img->alpha_layer) {
+ if (alpha) {
int i, c, r;
- uint32_t col[2] = { 0xFF666666, 0xFF999999 };
- uint32_t *data = imlib_image_get_data();
+ DATA32 col[2] = { 0xFF666666, 0xFF999999 };
+ DATA32 * data = imlib_image_get_data();
for (r = 0; r < dh; r++) {
i = r * dw;
@@ -490,41 +513,43 @@ void img_render(img_t *img)
}
imlib_image_put_back_data(data);
} else {
- XColor c = win->win_bg;
- imlib_context_set_color(c.red >> 8, c.green >> 8, c.blue >> 8, 0xFF);
+ imlib_image_clear();
+ c = win->win_bg_postmul;
+ imlib_context_set_color(c.red >> 8, c.green >> 8, c.blue >> 8,
+ win->win_alpha);
imlib_image_fill_rectangle(0, 0, dw, dh);
- }
- imlib_context_set_blend(1);
- imlib_context_set_operation(IMLIB_OP_COPY);
- imlib_blend_image_onto_image(img->im, 0, sx, sy, sw, sh, 0, 0, dw, dh);
+
+
+ imlib_blend_image_onto_image(im, 1, sx, sy, sw, sh, 0, 0, dw, dh);
imlib_context_set_color_modifier(NULL);
+
+ if (!alpha && win->win_alpha < 0xFF) {
+ /* blend onto black to get premultiplied alpha */
+ if ((bbg = imlib_create_image(dw, dh)) == NULL)
+ error(EXIT_FAILURE, ENOMEM, NULL);
+ imlib_context_set_image(bbg);
+ imlib_image_set_has_alpha(1);
+ imlib_context_set_color(0, 0, 0, 0xFF);
+ imlib_image_fill_rectangle(0, 0, dw, dh);
+ imlib_blend_image_onto_image(bg, 1, 0, 0, dw, dh, 0, 0, dw, dh);
+ imlib_image_copy_alpha_to_image(bg, 0, 0);
+ imlib_context_set_image(bg);
+ imlib_free_image();
+ imlib_context_set_image(bbg);
+ }
+
+ imlib_context_set_blend(0);
imlib_render_image_on_drawable(dx, dy);
+ imlib_context_set_blend(1);
imlib_free_image();
- imlib_context_set_color_modifier(img->cmod);
- } else {
-fallback:
+ imlib_context_set_color_modifier(cmod);
+ }} else {
+ imlib_image_set_has_alpha(1);
+ imlib_context_set_blend(0);
imlib_render_image_part_on_drawable_at_size(sx, sy, sw, sh, dx, dy, dw, dh);
- }
- img->dirty = false;
-}
-
-bool img_fit_win(img_t *img, scalemode_t sm)
-{
- float oz;
-
- oz = img->zoom;
- img->scalemode = sm;
-
- if (img_fit(img)) {
- img->x = img->win->w / 2 - (img->win->w / 2 - img->x) * img->zoom / oz;
- img->y = img->win->h / 2 - (img->win->h / 2 - img->y) * img->zoom / oz;
- img->checkpan = true;
- return true;
- } else {
- return false;
+ imlib_context_set_blend(1);
}
}
-
bool img_zoom_to(img_t *img, float z)
{
int x, y;
diff --git a/nsxiv.h b/nsxiv.h
index 1711c26..46aab2d 100644
--- a/nsxiv.h
+++ b/nsxiv.h
@@ -230,6 +230,7 @@ void img_update_color_modifiers(img_t*);
bool img_change_color_modifier(img_t*, int, int*);
bool img_frame_navigate(img_t*, int);
bool img_frame_animate(img_t*);
+void render_core(win_t*, int, int, int, int, int, int, int, int, bool);
Imlib_Image img_open(const fileinfo_t*);
#if HAVE_LIBEXIF
void exif_auto_orientate(const fileinfo_t*);
@@ -407,9 +408,11 @@ struct win {
Window xwin;
win_env_t env;
- XColor win_bg;
+ XColor win_bg; /* pre-multiplied alpha */
+ XColor win_bg_postmul; /* post-multiplied alpha */
XColor win_fg;
XColor mrk_fg;
+ unsigned int win_alpha;
#if HAVE_LIBFONTS
XftColor bar_bg;
XftColor bar_fg;
diff --git a/thumbs.c b/thumbs.c
index be887e4..dd0dbaa 100644
--- a/thumbs.c
+++ b/thumbs.c
@@ -489,7 +489,7 @@ void tns_render(tns_t *tns)
t->x = x + (thumb_sizes[tns->zl] - t->w) / 2;
t->y = y + (thumb_sizes[tns->zl] - t->h) / 2;
imlib_context_set_image(t->im);
- imlib_render_image_on_drawable_at_size(t->x, t->y, t->w, t->h);
+ render_core(win, 0, 0, t->w, t->h, t->x, t->y, t->w, t->h, false);
if (tns->files[i].flags & FF_MARK)
tns_mark(tns, i, true);
} else {
diff --git a/window.c b/window.c
index 42c3f2b..0fc7783 100644
--- a/window.c
+++ b/window.c
@@ -117,7 +117,7 @@ static const char *win_res(XrmDatabase db, const char *name, const char *def)
void win_init(win_t *win)
{
win_env_t *e;
- const char *win_bg, *win_fg, *mrk_fg;
+ const char *win_bg, *win_fg, *mrk_fg, *win_alpha;
char *res_man;
XrmDatabase db;
#if HAVE_LIBFONTS
@@ -125,7 +125,9 @@ void win_init(win_t *win)
static char lbuf[512 + UTF8_PADDING], rbuf[64 + UTF8_PADDING];
#endif
-
+ XVisualInfo vis;
+ float alpha;
+ char *endptr;
memset(win, 0, sizeof(*win));
e = &win->env;
@@ -135,9 +137,16 @@ void win_init(win_t *win)
e->scr = DefaultScreen(e->dpy);
e->scrw = DisplayWidth(e->dpy, e->scr);
e->scrh = DisplayHeight(e->dpy, e->scr);
- e->depth = DefaultDepth(e->dpy, e->scr);
- e->vis = DefaultVisual(e->dpy, e->scr);
- e->cmap = DefaultColormap(e->dpy, e->scr);
+
+ if (XMatchVisualInfo(e->dpy, e->scr, 32, TrueColor, &vis)) {
+ e->depth = 32;
+ e->vis = vis.visual;
+ e->cmap = XCreateColormap(e->dpy, DefaultRootWindow(e->dpy), e->vis, None);
+ } else {
+ e->depth = DefaultDepth(e->dpy, e->scr);
+ e->vis = DefaultVisual(e->dpy, e->scr);
+ e->cmap = DefaultColormap(e->dpy, e->scr);
+ }
if (setlocale(LC_CTYPE, "") == NULL || XSupportsLocale() == 0)
error(0, 0, "No locale support");
@@ -153,6 +162,25 @@ void win_init(win_t *win)
win_alloc_color(e, win_fg, &win->win_fg);
win_alloc_color(e, mrk_fg, &win->mrk_fg);
+ /* apply alpha */
+ win->win_bg_postmul = win->win_bg;
+ win_alpha = "0.0"; // win_res(db, RES_CLASS ".window.alpha", "1.0"); // NOTE: edited by swomf :)
+ alpha = strtof(win_alpha, &endptr);
+ if (!(*endptr == '\0' && alpha >= 0.0 && alpha <= 1.0))
+ error(EXIT_FAILURE, 0, "Error parsing alpha");
+ win->win_alpha = 0xFF;
+ if (e->depth == 32 && alpha < 1.0) {
+ win->win_alpha *= alpha;
+ win->win_bg.red *= alpha;
+ win->win_bg.green *= alpha;
+ win->win_bg.blue *= alpha;
+ win->win_bg.pixel =
+ (((unsigned long) win->win_bg.blue >> 8) << 0) |
+ (((unsigned long) win->win_bg.green >> 8) << 8) |
+ (((unsigned long) win->win_bg.red >> 8) << 16) |
+ (((unsigned long) win->win_alpha ) << 24);
+ }
+
#if HAVE_LIBFONTS
bar_bg = win_res(db, BAR_BG[0], BAR_BG[1] ? BAR_BG[1] : win_bg);
bar_fg = win_res(db, BAR_FG[0], BAR_FG[1] ? BAR_FG[1] : win_fg);