diff --git a/main.c b/main.c
index 3b5f9b9..936be3e 100644
--- a/main.c
+++ b/main.c
@@ -39,8 +39,10 @@
 #include "config.h"
 
 enum {
-	INFO_STR_LEN = 256,
-	FILENAME_CNT = 1024
+	BAR_L_LEN    = 512,
+	BAR_R_LEN    = 64,
+	FILENAME_CNT = 1024,
+	TITLE_LEN    = 256
 };
 
 typedef struct {
@@ -63,15 +65,18 @@ win_t win;
 fileinfo_t *files;
 int filecnt, fileidx;
 int alternate;
-size_t filesize;
 
 int prefix;
 
 bool resized = false;
 
-char win_bar_l[INFO_STR_LEN];
-char win_bar_r[INFO_STR_LEN];
-char win_title[INFO_STR_LEN];
+const char * const INFO_SCRIPT = ".sxiv/exec/image-info";
+char *info_script;
+
+struct {
+	char l[BAR_L_LEN];
+	char r[BAR_R_LEN];
+} bar;
 
 timeout_t timeouts[] = {
 	{ { 0, 0 }, false, redraw },
@@ -202,9 +207,37 @@ bool check_timeouts(struct timeval *t) {
 	return tmin > 0;
 }
 
-void load_image(int new) {
-	struct stat fstats;
+void read_info(void) {
+	char cmd[4096];
+	FILE *outp;
+	int c, i = 0, n = sizeof(bar.l) - 1;
+	bool lastsep = false;
+	
+	if (info_script != NULL) {
+		snprintf(cmd, sizeof(cmd), "%s \"%s\"", info_script, files[fileidx].name);
+		outp = popen(cmd, "r");
+		if (outp == NULL)
+			goto end;
+		while (i < n && (c = fgetc(outp)) != EOF) {
+			if (c == '\n') {
+				if (!lastsep) {
+					bar.l[i++] = ' ';
+					lastsep = true;
+				}
+			} else {
+				bar.l[i++] = c;
+				lastsep = false;
+			}
+		}
+		pclose(outp);
+	}
+end:
+	if (lastsep)
+		i--;
+	bar.l[i] = '\0';
+}
 
+void load_image(int new) {
 	if (new < 0 || new >= filecnt)
 		return;
 
@@ -220,10 +253,8 @@ void load_image(int new) {
 	files[new].loaded = true;
 	alternate = fileidx;
 	fileidx = new;
-	if (stat(files[new].path, &fstats) == 0)
-		filesize = fstats.st_size;
-	else
-		filesize = 0;
+
+	read_info();
 
 	if (img.multi.cnt > 0 && img.multi.animate)
 		set_timeout(animate, img.multi.frames[img.multi.sel].delay, true);
@@ -232,60 +263,51 @@ void load_image(int new) {
 }
 
 void update_info(void) {
-	int i, fw, pw, fi, ln, rn;
-	char frame_info[16];
-	const char *size_unit;
-	float size = filesize;
+	unsigned int i, fn, fw, n, len = sizeof(bar.r);
+	int sel;
+	char *t = bar.r, title[TITLE_LEN];
+	bool ow_info;
 
-	pw = 0;
-	for (i = filecnt; i > 0; i /= 10)
-		pw++;
+	for (fw = 0, i = filecnt; i > 0; fw++, i /= 10);
+	sel = mode == MODE_IMAGE ? fileidx : tns.sel;
 
 	if (mode == MODE_THUMB) {
-		if (tns.cnt != filecnt) {
-			snprintf(win_bar_l, sizeof win_bar_l, "Loading... %0*d/%d",
-			         pw, tns.cnt, filecnt);
+		win_set_title(&win, "sxiv");
+
+		if (tns.cnt == filecnt) {
+			n = snprintf(t, len, "%0*d/%d", fw, sel + 1, filecnt);
+			ow_info = true;
 		} else {
-			fi = snprintf(win_bar_l, sizeof win_bar_l, "%0*d/%d%s",
-			              pw, tns.sel + 1, filecnt, BAR_SEPARATOR);
-			ln = snprintf(win_bar_l + fi, sizeof win_bar_l - fi, "%s",
-			              files[tns.sel].name) + fi;
-			if (win_textwidth(win_bar_l, ln, true) > win.w)
-				snprintf(win_bar_l + fi, sizeof win_bar_l - fi, "%s",
-				         files[tns.sel].base);
+			snprintf(bar.l, sizeof(bar.l), "Loading... %0*d/%d",
+			         fw, tns.cnt, filecnt);
+			bar.r[0] = '\0';
+			ow_info = false;
 		}
-		win_set_title(&win, "sxiv");
-		win_set_bar_info(&win, win_bar_l, NULL);
 	} else {
-		size_readable(&size, &size_unit);
+		snprintf(title, sizeof(title), "sxiv - %s", files[sel].name);
+		win_set_title(&win, title);
+
+		n = snprintf(t, len, "%3d%% ", (int) (img.zoom * 100.0));
 		if (img.multi.cnt > 0) {
-			fw = 0;
-			for (i = img.multi.cnt; i > 0; i /= 10)
-				fw++;
-			snprintf(frame_info, sizeof frame_info, "%s%0*d/%d",
-			         BAR_SEPARATOR, fw, img.multi.sel+1, img.multi.cnt);
-		} else {
-			frame_info[0] = '\0';
+			for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10);
+			n += snprintf(t + n, len - n, "(%0*d/%d) ",
+			              fn, img.multi.sel + 1, img.multi.cnt);
 		}
-		fi = snprintf(win_bar_l, sizeof win_bar_l, "%0*d/%d%s",
-		              pw, fileidx + 1, filecnt, BAR_SEPARATOR);
-		ln = snprintf(win_bar_l + fi, sizeof win_bar_l - fi, "%s",
-		              files[fileidx].name) + fi;
-		rn = snprintf(win_bar_r, sizeof win_bar_r, "%.2f%s%s%dx%d%s%3d%%%s",
-		              size, size_unit, BAR_SEPARATOR, img.w, img.h, BAR_SEPARATOR,
-		              (int) (img.zoom * 100.0), frame_info);
-
-		if (win_textwidth(win_bar_l, ln, true) +
-		    win_textwidth(win_bar_r, rn, true) > win.w)
+		n += snprintf(t + n, len - n, "%0*d/%d", fw, sel + 1, filecnt);
+		ow_info = bar.l[0] == '\0';
+	}
+	if (ow_info) {
+		fn = strlen(files[sel].name);
+		if (fn < sizeof(bar.l) &&
+		    win_textwidth(files[sel].name, fn, true) +
+		    win_textwidth(bar.r, n, true) < win.w)
 		{
-			snprintf(win_bar_l + fi, sizeof win_bar_l - fi, "%s",
-			         files[fileidx].base);
+			strncpy(bar.l, files[sel].name, sizeof(bar.l));
+		} else {
+			strncpy(bar.l, files[sel].base, sizeof(bar.l));
 		}
-		win_set_bar_info(&win, win_bar_l, win_bar_r);
-
-		snprintf(win_title, sizeof win_title, "sxiv - %s", files[fileidx].name);
-		win_set_title(&win, win_title);
 	}
+	win_set_bar_info(&win, bar.l, bar.r);
 }
 
 void redraw(void) {
@@ -519,6 +541,7 @@ int main(int argc, char **argv) {
 	size_t n;
 	ssize_t len;
 	char *filename;
+	const char *homedir;
 	struct stat fstats;
 	r_dir_t dir;
 
@@ -595,6 +618,18 @@ int main(int argc, char **argv) {
 	win_init(&win);
 	img_init(&img, &win);
 
+	if ((homedir = getenv("HOME")) == NULL) {
+		warn("could not locate home directory");
+	} else {
+		len = strlen(homedir) + strlen(INFO_SCRIPT) + 2;
+		info_script = (char*) s_malloc(len);
+		snprintf(info_script, len, "%s/%s", homedir, INFO_SCRIPT);
+		if (access(info_script, X_OK) != 0) {
+			free(info_script);
+			info_script = NULL;
+		}
+	}
+
 	if (options->thumb_mode) {
 		mode = MODE_THUMB;
 		tns_init(&tns, filecnt, &win);
diff --git a/window.c b/window.c
index 179e9c6..216cfc1 100644
--- a/window.c
+++ b/window.c
@@ -42,13 +42,16 @@ static GC gc;
 
 Atom wm_delete_win;
 
-struct {
+static struct {
 	int ascent;
 	int descent;
 	XFontStruct *xfont;
 	XFontSet set;
 } font;
 
+static int fontheight;
+static int barheight;
+
 void win_init_font(Display *dpy, const char *fontstr) {
 	int n;
 	char *def, **missing;
@@ -77,6 +80,8 @@ void win_init_font(Display *dpy, const char *fontstr) {
 		font.ascent  = font.xfont->ascent;
 		font.descent = font.xfont->descent;
 	}
+	fontheight = font.ascent + font.descent;
+	barheight = fontheight + 2 * V_TEXT_PAD;
 }
 
 unsigned long win_alloc_color(win_t *win, const char *name) {
@@ -85,8 +90,8 @@ unsigned long win_alloc_color(win_t *win, const char *name) {
 	if (win == NULL)
 		return 0UL;
 	if (XAllocNamedColor(win->env.dpy,
-		                   DefaultColormap(win->env.dpy, win->env.scr),
-											 name, &col, &col) == 0)
+	                     DefaultColormap(win->env.dpy, win->env.scr),
+	                     name, &col, &col) == 0)
 	{
 		die("could not allocate color: %s", name);
 	}
@@ -99,6 +104,8 @@ void win_init(win_t *win) {
 	if (win == NULL)
 		return;
 
+	memset(win, 0, sizeof(win_t));
+
 	e = &win->env;
 	if ((e->dpy = XOpenDisplay(NULL)) == NULL)
 		die("could not open display");
@@ -110,19 +117,12 @@ void win_init(win_t *win) {
 	e->cmap = DefaultColormap(e->dpy, e->scr);
 	e->depth = DefaultDepth(e->dpy, e->scr);
 
-	win->white    = WhitePixel(e->dpy, e->scr);
-	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->barbgcol = win_alloc_color(win, BAR_BG_COLOR);
-	win->barfgcol = win_alloc_color(win, BAR_FG_COLOR);
-
-	win->xwin = 0;
-	win->pm = 0;
-	win->fullscreen = false;
-	win->barh = 0;
-	win->lbar = NULL;
-	win->rbar = NULL;
+	win->white     = WhitePixel(e->dpy, e->scr);
+	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);
 
 	if (setlocale(LC_CTYPE, "") == NULL || XSupportsLocale() == 0)
 		warn("no locale support");
@@ -141,8 +141,8 @@ void win_set_sizehints(win_t *win) {
 	sizehints.flags = PMinSize | PMaxSize;
 	sizehints.min_width = win->w;
 	sizehints.max_width = win->w;
-	sizehints.min_height = win->h + win->barh;
-	sizehints.max_height = win->h + win->barh;
+	sizehints.min_height = win->h + win->bar.h;
+	sizehints.max_height = win->h + win->bar.h;
 	XSetWMNormalHints(win->env.dpy, win->xwin, &sizehints);
 }
 
@@ -215,8 +215,8 @@ void win_open(win_t *win) {
 	XSetWMProtocols(e->dpy, win->xwin, &wm_delete_win, 1);
 
 	if (!options->hide_bar) {
-		win->barh = font.ascent + font.descent + 2 * V_TEXT_PAD;
-		win->h -= win->barh;
+		win->bar.h = barheight;
+		win->h -= win->bar.h;
 	}
 
 	if (options->fixed_win)
@@ -249,8 +249,8 @@ bool win_configure(win_t *win, XConfigureEvent *c) {
 
 	if (win == NULL || c == NULL)
 		return false;
-	
-	if ((changed = win->w != c->width || win->h + win->barh != c->height)) {
+
+	if ((changed = win->w != c->width || win->h + win->bar.h != c->height)) {
 		if (win->pm != None) {
 			XFreePixmap(win->env.dpy, win->pm);
 			win->pm = None;
@@ -260,7 +260,7 @@ bool win_configure(win_t *win, XConfigureEvent *c) {
 	win->x = c->x;
 	win->y = c->y;
 	win->w = c->width;
-	win->h = c->height - win->barh;
+	win->h = c->height - win->bar.h;
 	win->bw = c->border_width;
 
 	return changed;
@@ -283,13 +283,13 @@ bool win_moveresize(win_t *win, int x, int y, unsigned int w, unsigned int h) {
 	w = MIN(w, win->env.scrw - 2 * win->bw);
 	h = MIN(h, win->env.scrh - 2 * win->bw);
 
-	if (win->x == x && win->y == y && win->w == w && win->h + win->barh == h)
+	if (win->x == x && win->y == y && win->w == w && win->h + win->bar.h == h)
 		return false;
 
 	win->x = x;
 	win->y = y;
 	win->w = w;
-	win->h = h - win->barh;
+	win->h = h - win->bar.h;
 
 	if (options->fixed_win)
 		win_set_sizehints(win);
@@ -327,12 +327,12 @@ void win_toggle_bar(win_t *win) {
 	if (win == NULL || win->xwin == None)
 		return;
 
-	if (win->barh != 0) {
-		win->h += win->barh;
-		win->barh = 0;
+	if (win->bar.h != 0) {
+		win->h += win->bar.h;
+		win->bar.h = 0;
 	} else {
-		win->barh = font.ascent + font.descent + 2 * V_TEXT_PAD;
-		win->h -= win->barh;
+		win->bar.h = barheight;
+		win->h -= win->bar.h;
 	}
 }
 
@@ -343,7 +343,7 @@ void win_clear(win_t *win) {
 	if (win == NULL || win->xwin == None)
 		return;
 
-	h = win->h + win->barh;
+	h = win->h + win->bar.h;
 	e = &win->env;
 
 	if (win->pm == None)
@@ -354,53 +354,56 @@ void win_clear(win_t *win) {
 }
 
 void win_draw_bar(win_t *win) {
+	int len, olen, x, y, w, tw;
+	char rest[3];
+	const char *dots = "...";
 	win_env_t *e;
-	int len, x, y, w, tw = 0, seplen;
-	const char *rt;
 
 	if (win == NULL || win->xwin == None || win->pm == None)
 		return;
 
 	e = &win->env;
-	x = H_TEXT_PAD;
 	y = win->h + font.ascent + V_TEXT_PAD;
-	w = win->w - 2 * H_TEXT_PAD;
+	w = win->w;
 
-	XSetForeground(e->dpy, gc, win->barbgcol);
-	XFillRectangle(e->dpy, win->pm, gc, 0, win->h, win->w, win->barh);
+	XSetForeground(e->dpy, gc, win->bar.bgcol);
+	XFillRectangle(e->dpy, win->pm, gc, 0, win->h, win->w, win->bar.h);
 
-	XSetForeground(e->dpy, gc, win->barfgcol);
-	XSetBackground(e->dpy, gc, win->barbgcol);
+	XSetForeground(e->dpy, gc, win->bar.fgcol);
+	XSetBackground(e->dpy, gc, win->bar.bgcol);
 
-	if (win->lbar != NULL) {
-		len = strlen(win->lbar);
-		while (len > 0 && (tw = win_textwidth(win->lbar, len, false)) > w)
-			len--;
-		w -= tw + 2 * H_TEXT_PAD;
-		if (font.set)
-			XmbDrawString(e->dpy, win->pm, font.set, gc, x, y, win->lbar, len);
-		else
-			XDrawString(e->dpy, win->pm, gc, x, y, win->lbar, len);
-	}
-	if (win->rbar != NULL) {
-		len = strlen(win->rbar);
-		seplen = strlen(BAR_SEPARATOR);
-		rt = win->rbar;
-		while (len > 0 && (tw = win_textwidth(rt, len, false)) > w) {
-			rt = strstr(rt, BAR_SEPARATOR);
-			if (rt != NULL) {
-				rt += seplen;
-				len = strlen(rt);
-			} else {
-				len = 0;
-			}
+	if (win->bar.r != NULL) {
+		len = strlen(win->bar.r);
+		if (len > 0) {
+			if ((tw = win_textwidth(win->bar.r, len, true)) > w)
+				return;
+			x = win->w - tw + H_TEXT_PAD;
+			w -= tw;
+			if (font.set)
+				XmbDrawString(e->dpy, win->pm, font.set, gc, x, y, win->bar.r, len);
+			else
+				XDrawString(e->dpy, win->pm, gc, x, y, win->bar.r, len);
 		}
+	}
+	if (win->bar.l != NULL) {
+		olen = len = strlen(win->bar.l);
+		while (len > 0 && (tw = win_textwidth(win->bar.l, len, true)) > w)
+			len--;
 		if (len > 0) {
-			x = win->w - tw - H_TEXT_PAD;
+      if (len != olen) {
+        w = strlen(dots);
+        if (len <= w)
+          return;
+        memcpy(rest, win->bar.l + len - w, w);
+        memcpy(win->bar.l + len - w, dots, w);
+      }
+			x = H_TEXT_PAD;
 			if (font.set)
-				XmbDrawString(e->dpy, win->pm, font.set, gc, x, y, rt, len);
+				XmbDrawString(e->dpy, win->pm, font.set, gc, x, y, win->bar.l, len);
 			else
-				XDrawString(e->dpy, win->pm, gc, x, y, rt, len);
+				XDrawString(e->dpy, win->pm, gc, x, y, win->bar.l, len);
+			if (len != olen)
+			  memcpy(win->bar.l + len - w, rest, w);
 		}
 	}
 }
@@ -409,11 +412,11 @@ void win_draw(win_t *win) {
 	if (win == NULL || win->xwin == None || win->pm == None)
 		return;
 
-	if (win->barh > 0)
+	if (win->bar.h > 0)
 		win_draw_bar(win);
 
 	XCopyArea(win->env.dpy, win->pm, win->xwin, gc,
-	          0, 0, win->w, win->h + win->barh, 0, 0);
+	          0, 0, win->w, win->h + win->bar.h, 0, 0);
 }
 
 void win_draw_rect(win_t *win, Pixmap pm, int x, int y, int w, int h,
@@ -466,10 +469,10 @@ void win_set_title(win_t *win, const char *title) {
 	                PropModeReplace, (unsigned char *) title, strlen(title));
 }
 
-void win_set_bar_info(win_t *win, const char *li, const char *ri) {
+void win_set_bar_info(win_t *win, char *linfo, char *rinfo) {
 	if (win != NULL) {
-		win->lbar = li;
-		win->rbar = ri;
+		win->bar.l = linfo;
+		win->bar.r = rinfo;
 	}
 }
 
diff --git a/window.h b/window.h
index 5e033e3..6bc6595 100644
--- a/window.h
+++ b/window.h
@@ -23,8 +23,6 @@
 
 #include "types.h"
 
-#define BAR_SEPARATOR " | "
-
 typedef struct {
 	Display *dpy;
 	int scr;
@@ -42,21 +40,23 @@ typedef struct {
 	unsigned long bgcol;
 	unsigned long fscol;
 	unsigned long selcol;
-	unsigned long barbgcol;
-	unsigned long barfgcol;
 	Pixmap pm;
 
 	int x;
 	int y;
 	unsigned int w;
 	unsigned int h; /* = win height - bar height */
-	unsigned int barh;
 	unsigned int bw;
 
 	bool fullscreen;
 
-	const char *lbar;
-	const char *rbar;
+	struct {
+		unsigned int h;
+		char *l;
+		char *r;
+		unsigned long bgcol;
+		unsigned long fgcol;
+	} bar;
 } win_t;
 
 extern Atom wm_delete_win;
@@ -80,7 +80,7 @@ void win_draw_rect(win_t*, Pixmap, int, int, int, int, bool, int,
 int win_textwidth(const char*, unsigned int, bool);
 
 void win_set_title(win_t*, const char*);
-void win_set_bar_info(win_t*, const char*, const char*);
+void win_set_bar_info(win_t*, char*, char*);
 void win_set_cursor(win_t*, cursor_t);
 
 #endif /* WINDOW_H */