diff --git a/Makefile b/Makefile index 3527741..fab8041 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,8 @@ install: all mkdir -p $(DESTDIR)$(EGPREFIX) cp etc/examples/* $(DESTDIR)$(EGPREFIX) chmod 755 $(DESTDIR)$(EGPREFIX)/* + @echo "INSTALL bin/nsxiv-dirchanger" + cp nsxiv-dirchanger $(DESTDIR)$(PREFIX)/bin/ uninstall: uninstall-icon @echo "REMOVE bin/nsxiv" @@ -108,4 +110,5 @@ uninstall: uninstall-icon rm -f $(DESTDIR)$(PREFIX)/share/applications/nsxiv.desktop @echo "REMOVE share/nsxiv/" rm -rf $(DESTDIR)$(EGPREFIX) - + @echo "REMOVE bin/nsxiv-dirchanger" + rm -rf $(DESTDIR)$(PREFIX)/bin/nsxiv-dirchanger diff --git a/commands.c b/commands.c index 7c44ace..25b7df9 100644 --- a/commands.c +++ b/commands.c @@ -246,6 +246,50 @@ bool cg_change_contrast(arg_t d) return change_color_modifier(d, &img.contrast); } +bool cg_dmenu_search(arg_t _) +{ + extern char nsxiv_xid[64]; + extern const char *const dmenu_search_cmd[]; + + char output[4096]; + int i, rfd, wfd, goto_img = -1; + ssize_t n; + + snprintf(nsxiv_xid, sizeof nsxiv_xid, "0x%.8lX", win.xwin); + if (spawn(&rfd, &wfd, (char **)dmenu_search_cmd) < 0) + return false; + for (i = 0; i < filecnt; ++i) { + dprintf(wfd, "%s\n", files[i].name); + } + close(wfd); + if ((n = read(rfd, output, sizeof output - 1)) > 0) { + char *e = memchr(output, '\n', n); + if (e != NULL) + *e = '\0'; + else + output[n] = '\0'; + for (i = 0; i < filecnt; ++i) { + if (STREQ(output, files[i].name)) { + goto_img = i; + break; + } + } + } + close(rfd); + + return navigate_to(goto_img); +} + + +bool cg_toggle_invert(arg_t _) +{ + img.invert = !img.invert; + img_update_color_modifiers(&img); + if (mode == MODE_THUMB) + tns.dirty = true; + return true; +} + bool ci_navigate(arg_t n) { if (prefix > 0) @@ -478,3 +522,4 @@ bool ct_select(arg_t _) return dirty; } + diff --git a/commands.h b/commands.h index 76b1330..d988f2c 100644 --- a/commands.h +++ b/commands.h @@ -6,6 +6,7 @@ bool cg_change_gamma(arg_t); bool cg_change_brightness(arg_t); bool cg_change_contrast(arg_t); +bool cg_toggle_invert(arg_t); bool cg_first(arg_t); bool cg_mark_range(arg_t); bool cg_n_or_last(arg_t); @@ -22,6 +23,8 @@ bool cg_toggle_fullscreen(arg_t); bool cg_toggle_image_mark(arg_t); bool cg_unmark_all(arg_t); bool cg_zoom(arg_t); +bool cg_dmenu_search(arg_t); +bool cg_dmenu_cd(arg_t); /* image mode */ bool ci_alternate(arg_t); bool ci_cursor_navigate(arg_t); @@ -51,6 +54,7 @@ bool ct_select(arg_t); #define g_change_gamma { cg_change_gamma, MODE_ALL } #define g_change_brightness { cg_change_brightness, MODE_ALL } #define g_change_contrast { cg_change_contrast, MODE_ALL } +#define g_toggle_invert { cg_toggle_invert, MODE_ALL } #define g_first { cg_first, MODE_ALL } #define g_mark_range { cg_mark_range, MODE_ALL } #define g_n_or_last { cg_n_or_last, MODE_ALL } @@ -67,6 +71,8 @@ bool ct_select(arg_t); #define g_toggle_image_mark { cg_toggle_image_mark, MODE_ALL } #define g_unmark_all { cg_unmark_all, MODE_ALL } #define g_zoom { cg_zoom, MODE_ALL } +#define g_dmenu_search { cg_dmenu_search, MODE_ALL } +#define g_dmenu_cd { cg_dmenu_cd, MODE_ALL } /* image mode */ #define i_alternate { ci_alternate, MODE_IMAGE } @@ -95,3 +101,4 @@ bool ct_select(arg_t); #endif /* _MAPPINGS_CONFIG */ #endif /* COMMANDS_H */ + diff --git a/config.def.h b/config.def.h index a0935f6..f4ff7f3 100644 --- a/config.def.h +++ b/config.def.h @@ -13,7 +13,7 @@ static const char *DEFAULT_MARK_COLOR = NULL; /* NULL means it will default to #if HAVE_LIBFONTS static const char *DEFAULT_BAR_BG = NULL; /* NULL means it will default to window background */ static const char *DEFAULT_BAR_FG = NULL; /* NULL means it will default to window foreground */ -static const char *DEFAULT_FONT = "monospace-8"; +static const char *DEFAULT_FONT = "monospace-12"; /* if true, statusbar appears on top of the window */ static const bool TOP_STATUSBAR = false; @@ -82,12 +82,18 @@ static const int THUMB_SIZE = 3; #endif #ifdef INCLUDE_MAPPINGS_CONFIG +char nsxiv_xid[64]; /* will be set to nsxiv's xid when dmenu_search is invoked */ +const char *const dmenu_search_cmd[] = { + "dmenu", "-l", "16", "-i", NULL +}; +const char *const dmenu_cd_cmd[] = { + "nsxiv-dirchanger", NULL +}; /* these modifiers will be used when processing keybindings */ static const unsigned int USED_MODMASK = ShiftMask | ControlMask | Mod1Mask; /* abort the keyhandler */ static const KeySym KEYHANDLER_ABORT = XK_Escape; - /* keyboard mappings for image and thumbnail mode: */ static const keymap_t keys[] = { /* modifiers key function argument */ @@ -100,6 +106,8 @@ static const keymap_t keys[] = { { 0, XK_G, g_n_or_last, None }, { 0, XK_r, g_reload_image, None }, { 0, XK_D, g_remove_image, None }, + { 0, XK_slash, g_dmenu_search, None }, + { ControlMask, XK_d, g_dmenu_cd, None}, { ControlMask, XK_h, g_scroll_screen, DIR_LEFT }, { ControlMask, XK_Left, g_scroll_screen, DIR_LEFT }, { ControlMask, XK_j, g_scroll_screen, DIR_DOWN }, @@ -125,6 +133,7 @@ static const keymap_t keys[] = { { ControlMask, XK_bracketleft, g_change_brightness, -1 }, { 0, XK_parenleft, g_change_contrast, -1 }, { 0, XK_parenright, g_change_contrast, +1 }, + { 0, XK_i, g_toggle_invert, None }, { 0, XK_h, t_move_sel, DIR_LEFT }, { 0, XK_Left, t_move_sel, DIR_LEFT }, @@ -211,3 +220,4 @@ static const cursor_t imgcursor[3] = { }; #endif + diff --git a/image.c b/image.c index 42979c7..9fa0fad 100644 --- a/image.c +++ b/image.c @@ -101,6 +101,7 @@ void img_init(img_t *img, win_t *win) imlib_context_set_color_modifier(img->cmod); img->brightness = 0; img->contrast = 0; + img->invert = false; img_change_color_modifier(img, options->gamma, &img->gamma); img->ss.on = options->slideshow > 0; @@ -702,12 +703,81 @@ static bool img_fit(img_t *img) } } +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()) { + 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(1); + + if (alpha) { + int i, c, r; + DATA32 col[2] = { 0xFF666666, 0xFF999999 }; + DATA32 * data = imlib_image_get_data(); + + for (r = 0; r < dh; r++) { + i = r * dw; + if (r == 0 || r == 8) { + for (c = 0; c < dw; c++) + data[i++] = col[!(c & 8) ^ !r]; + } else { + memcpy(&data[i], &data[(r & 8) * dw], dw * sizeof(data[0])); + } + } + imlib_image_put_back_data(data); + } else { + 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_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(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); + imlib_context_set_blend(1); + } +} + + 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); @@ -756,45 +826,7 @@ void img_render(img_t *img) /* manual blending, for performance reasons. * see https://phab.enlightenment.org/T8969#156167 for more details. */ - if (imlib_image_has_alpha()) { - if ((bg = imlib_create_image(dw, dh)) == NULL) { - error(0, ENOMEM, "Failed to create image"); - goto fallback; - } - imlib_context_set_image(bg); - imlib_image_set_has_alpha(0); - - if (img->alpha_layer) { - int i, c, r; - uint32_t col[2] = { 0xFF666666, 0xFF999999 }; - uint32_t *data = imlib_image_get_data(); - - for (r = 0; r < dh; r++) { - i = r * dw; - if (r == 0 || r == 8) { - for (c = 0; c < dw; c++) - data[i++] = col[!(c & 8) ^ !r]; - } else { - memcpy(&data[i], &data[(r & 8) * dw], dw * sizeof(data[0])); - } - } - 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_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_context_set_color_modifier(NULL); - imlib_render_image_on_drawable(dx, dy); - imlib_free_image(); - imlib_context_set_color_modifier(img->cmod); - } else { -fallback: - imlib_render_image_part_on_drawable_at_size(sx, sy, sw, sh, dx, dy, dw, dh); - } + render_core(win, sx, sy, sw, sh, dx, dy, dw, dh, img->alpha); img->dirty = false; } @@ -1016,6 +1048,19 @@ void img_update_color_modifiers(img_t *img) if (img->contrast != 0) imlib_modify_color_modifier_contrast(steps_to_range(img->contrast, CONTRAST_MAX, 1.0)); + if (img->invert) { + size_t i; + uint8_t r[256], g[256], b[256], a[256]; + + imlib_get_color_modifier_tables(r, g, b, a); + for (i = 0; i < ARRLEN(r); i++) { + r[i] = 255 - r[i]; + g[i] = 255 - g[i]; + b[i] = 255 - b[i]; + } + imlib_set_color_modifier_tables(r, g, b, a); + } + img->dirty = true; } @@ -1066,3 +1111,4 @@ bool img_frame_animate(img_t *img) else return false; } + diff --git a/main.c b/main.c index 3868e8e..55ee475 100644 --- a/main.c +++ b/main.c @@ -150,7 +150,6 @@ static void check_add_file(const char *filename, bool given) files[fileidx].flags |= FF_WARN; fileidx++; } - static void add_entry(const char *entry_name) { int start; @@ -180,6 +179,15 @@ static void add_entry(const char *entry_name) } } +void add_entry_test(){ + char * filename = "/home/alex/dls/pix/Wien_-_Michaelerkirche,_Hochaltar.JPG"; + fprintf(stdout, "Trying to add file %s to entries\n", filename); + add_entry(filename); + filecnt = fileidx; + fileidx = options->startnum < filecnt ? options->startnum : 0; + cg_reload_image(MODE_ALL); +} + void remove_file(int n, bool manual) { if (n < 0 || n >= filecnt) @@ -953,3 +961,37 @@ int main(int argc, char *argv[]) return 0; } + +bool cg_dmenu_cd(arg_t _){ + extern char nsxiv_xid[64]; + extern const char *const dmenu_cd_cmd[]; + + char output[4096]; + int i, rfd, wfd, goto_img = -1; + ssize_t n; + + snprintf(nsxiv_xid, sizeof nsxiv_xid, "0x%.8lX", win.xwin); + if (spawn(&rfd, &wfd, (char **)dmenu_cd_cmd) < 0) + return false; + for (i = 0; i < filecnt; ++i) { + dprintf(wfd, "%s\n", files[i].name); + } + close(wfd); + if ((n = read(rfd, output, sizeof output - 1)) > 0) { + char *e = memchr(output, '\n', n); + if (e != NULL) + *e = '\0'; + else + output[n] = '\0'; + + fprintf(stdout, "Trying to add file %s to entries\n", output); + add_entry(output); + filecnt = fileidx; + fileidx = options->startnum < filecnt ? options->startnum : 0; + cg_reload_image(MODE_ALL); + } + close(rfd); + + return True; +} + diff --git a/nsxiv.h b/nsxiv.h index 8011f9e..33ca25c 100644 --- a/nsxiv.h +++ b/nsxiv.h @@ -178,11 +178,13 @@ struct img { win_t *win; float x; float y; + float alpha; Imlib_Color_Modifier cmod; int gamma; int brightness; int contrast; + bool invert; scalemode_t scalemode; float zoom; @@ -218,6 +220,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*); @@ -382,9 +385,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; @@ -455,3 +460,4 @@ extern int prefix; extern bool title_dirty; #endif /* NSXIV_H */ + diff --git a/thumbs.c b/thumbs.c index c1778b5..a686cf2 100644 --- a/thumbs.c +++ b/thumbs.c @@ -442,7 +442,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 3857871..a9907df 100644 --- a/window.c +++ b/window.c @@ -112,9 +112,12 @@ 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; + XVisualInfo vis; + float alpha; + char *endptr; #if HAVE_LIBFONTS const char *bar_fg, *bar_bg, *f; @@ -130,9 +133,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"); @@ -148,6 +158,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 = win_res(db, RES_CLASS ".window.alpha", "1.0"); + 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, RES_CLASS ".bar.background", DEFAULT_BAR_BG ? DEFAULT_BAR_BG : win_bg); bar_fg = win_res(db, RES_CLASS ".bar.foreground", DEFAULT_BAR_FG ? DEFAULT_BAR_FG : win_fg); @@ -543,3 +572,4 @@ void win_cursor_pos(win_t *win, int *x, int *y) if (!XQueryPointer(win->env.dpy, win->xwin, &w, &w, &i, &i, x, y, &ui)) *x = *y = 0; } +