Revised thumbnail loading...

- Only load the thumbnails that are currently visible in the window
- Unload thumbnails that are leaving the visible area
- Much less memory needed, but scrolling is now slower
- This also unintentionally fixes issue #86
This commit is contained in:
Bert Münnich 2014-09-25 20:57:24 +02:00
parent 52e56c8924
commit eaa269b6cb
5 changed files with 71 additions and 45 deletions

View File

@ -1,4 +1,4 @@
VERSION = git-20140911 VERSION = git-20140926
PREFIX = /usr/local PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man MANPREFIX = $(PREFIX)/share/man

View File

@ -470,7 +470,8 @@ bool ct_reload_all(arg_t a)
{ {
tns_free(&tns); tns_free(&tns);
tns_init(&tns, files, filecnt, &fileidx, &win); tns_init(&tns, files, filecnt, &fileidx, &win);
return false; tns.dirty = true;
return true;
} }

33
main.c
View File

@ -368,14 +368,13 @@ void update_info(void)
return; return;
mark = files[fileidx].marked ? "+ " : ""; mark = files[fileidx].marked ? "+ " : "";
if (mode == MODE_THUMB) { if (mode == MODE_THUMB) {
if (tns.loadnext >= filecnt) { if (tns.loadnext < tns.end) {
n = snprintf(rt, rlen, "%s%0*d/%d", mark, fw, fileidx + 1, filecnt); snprintf(lt, llen, "Loading... %0*d", fw, tns.loadnext);
ow_info = true;
} else {
snprintf(lt, llen, "Loading... %0*d/%d", fw, tns.loadnext, filecnt);
rt[0] = '\0';
ow_info = false; ow_info = false;
} else {
ow_info = true;
} }
n = snprintf(rt, rlen, "%s%0*d/%d", mark, fw, fileidx + 1, filecnt);
} else { } else {
n = snprintf(rt, rlen, "%s", mark); n = snprintf(rt, rlen, "%s", mark);
if (img.ss.on) if (img.ss.on)
@ -439,7 +438,7 @@ void reset_cursor(void)
} }
} }
} else { } else {
if (tns.loadnext < filecnt) if (tns.loadnext < tns.end)
cursor = CURSOR_WATCH; cursor = CURSOR_WATCH;
else else
cursor = CURSOR_ARROW; cursor = CURSOR_ARROW;
@ -531,7 +530,7 @@ void run_key_handler(const char *key, unsigned int mask)
memcmp(&oldst->st_mtime, &newst.st_mtime, sizeof(newst.st_mtime)) != 0) memcmp(&oldst->st_mtime, &newst.st_mtime, sizeof(newst.st_mtime)) != 0)
{ {
if (tns.thumbs != NULL) { if (tns.thumbs != NULL) {
tns.thumbs[finfo[i].fn].loaded = false; tns_unload(&tns, finfo[i].fn);
tns.loadnext = MIN(tns.loadnext, finfo[i].fn); tns.loadnext = MIN(tns.loadnext, finfo[i].fn);
} }
changed = true; changed = true;
@ -669,29 +668,24 @@ void run(void)
int xfd; int xfd;
fd_set fds; fd_set fds;
struct timeval timeout; struct timeval timeout;
bool discard, reload, to_set; bool discard, to_set;
XEvent ev, nextev; XEvent ev, nextev;
set_timeout(redraw, 25, false); set_timeout(redraw, 25, false);
while (true) { while (true) {
while (mode == MODE_THUMB && tns.loadnext < filecnt && while (mode == MODE_THUMB && tns.loadnext < tns.end &&
XPending(win.env.dpy) == 0) XPending(win.env.dpy) == 0)
{ {
/* load thumbnails */ /* load thumbnails */
reload = tns.loadnext != tns.cnt;
set_timeout(redraw, TO_REDRAW_THUMBS, false); set_timeout(redraw, TO_REDRAW_THUMBS, false);
if (tns_load(&tns, tns.loadnext, reload)) { if (!tns_load(&tns, tns.loadnext, false)) {
if (!reload)
tns.cnt++;
} else {
remove_file(tns.loadnext, false); remove_file(tns.loadnext, false);
if (reload) tns.dirty = true;
tns.dirty = true;
} }
while (tns.loadnext < filecnt && tns.thumbs[tns.loadnext].loaded) while (tns.loadnext < tns.end && tns.thumbs[tns.loadnext].im != NULL)
tns.loadnext++; tns.loadnext++;
if (tns.loadnext >= filecnt) if (tns.loadnext >= tns.end)
redraw(); redraw();
else else
check_timeouts(NULL); check_timeouts(NULL);
@ -882,7 +876,6 @@ int main(int argc, char **argv)
tns_init(&tns, files, filecnt, &fileidx, &win); tns_init(&tns, files, filecnt, &fileidx, &win);
while (!tns_load(&tns, 0, false)) while (!tns_load(&tns, 0, false))
remove_file(0, false); remove_file(0, false);
tns.cnt = 1;
} else { } else {
mode = MODE_IMAGE; mode = MODE_IMAGE;
tns.thumbs = NULL; tns.thumbs = NULL;

View File

@ -56,7 +56,7 @@ char* tns_cache_filepath(const char *filepath)
return cfile; return cfile;
} }
Imlib_Image tns_cache_load(const char *filepath) Imlib_Image tns_cache_load(const char *filepath, bool *outdated)
{ {
char *cfile; char *cfile;
struct stat cstats, fstats; struct stat cstats, fstats;
@ -68,8 +68,12 @@ Imlib_Image tns_cache_load(const char *filepath)
return NULL; return NULL;
if ((cfile = tns_cache_filepath(filepath)) != NULL) { if ((cfile = tns_cache_filepath(filepath)) != NULL) {
if (stat(cfile, &cstats) == 0 && cstats.st_mtime == fstats.st_mtime) if (stat(cfile, &cstats) == 0) {
im = imlib_load_image(cfile); if (cstats.st_mtime == fstats.st_mtime)
im = imlib_load_image(cfile);
else
*outdated = true;
}
free(cfile); free(cfile);
} }
return im; return im;
@ -165,8 +169,8 @@ void tns_init(tns_t *tns, const fileinfo_t *files, int cnt, int *sel, win_t *win
tns->thumbs = NULL; tns->thumbs = NULL;
} }
tns->files = files; tns->files = files;
tns->cap = cnt; tns->cnt = cnt;
tns->cnt = tns->loadnext = tns->first = 0; tns->loadnext = tns->first = tns->end = tns->r_first = tns->r_end = 0;
tns->sel = sel; tns->sel = sel;
tns->win = win; tns->win = win;
tns->dirty = false; tns->dirty = false;
@ -218,7 +222,7 @@ bool tns_load(tns_t *tns, int n, bool force)
if (tns == NULL || tns->thumbs == NULL) if (tns == NULL || tns->thumbs == NULL)
return false; return false;
if (n < 0 || n >= tns->cap) if (n < 0 || n >= tns->cnt)
return false; return false;
file = &tns->files[n]; file = &tns->files[n];
if (file->name == NULL || file->path == NULL) if (file->name == NULL || file->path == NULL)
@ -231,7 +235,7 @@ bool tns_load(tns_t *tns, int n, bool force)
imlib_free_image(); imlib_free_image();
} }
if (!force && (im = tns_cache_load(file->path)) != NULL) { if (!force && (im = tns_cache_load(file->path, &force)) != NULL) {
cache_hit = true; cache_hit = true;
} else { } else {
#if HAVE_LIBEXIF #if HAVE_LIBEXIF
@ -323,11 +327,28 @@ bool tns_load(tns_t *tns, int n, bool force)
if (!cache_hit) if (!cache_hit)
tns_cache_write(t, file, true); tns_cache_write(t, file, true);
t->loaded = true;
tns->dirty = true; tns->dirty = true;
return true; return true;
} }
void tns_unload(tns_t *tns, int n)
{
thumb_t *t;
if (tns == NULL || tns->thumbs == NULL)
return;
if (n < 0 || n >= tns->cnt)
return;
t = &tns->thumbs[n];
if (t->im != NULL) {
imlib_context_set_image(t->im);
imlib_free_image();
t->im = NULL;
}
}
void tns_check_view(tns_t *tns, bool scrolled) void tns_check_view(tns_t *tns, bool scrolled)
{ {
int r; int r;
@ -385,20 +406,31 @@ void tns_render(tns_t *tns)
if (r > 0) if (r > 0)
cnt -= r % tns->cols; cnt -= r % tns->cols;
} }
r = cnt % tns->cols ? 1 : 0; r = cnt % tns->cols ? 1 : 0;
tns->x = x = (win->w - MIN(cnt, tns->cols) * thumb_dim) / 2 + 5; tns->x = x = (win->w - MIN(cnt, tns->cols) * thumb_dim) / 2 + 5;
tns->y = y = (win->h - (cnt / tns->cols + r) * thumb_dim) / 2 + 5; tns->y = y = (win->h - (cnt / tns->cols + r) * thumb_dim) / 2 + 5;
tns->loadnext = tns->cnt;
tns->end = tns->first + cnt;
for (i = 0; i < cnt; i++) { for (i = tns->r_first; i < tns->r_end; i++) {
t = &tns->thumbs[tns->first + i]; if ((i < tns->first || i >= tns->end) && tns->thumbs[i].im != NULL)
t->x = x + (THUMB_SIZE - t->w) / 2; tns_unload(tns, i);
t->y = y + (THUMB_SIZE - t->h) / 2; }
imlib_context_set_image(t->im); tns->r_first = tns->first;
imlib_render_image_part_on_drawable_at_size(0, 0, t->w, t->h, tns->r_end = tns->end;
t->x, t->y, t->w, t->h);
if (tns->files[tns->first + i].marked) for (i = tns->first; i < tns->end; i++) {
tns_mark(tns, tns->first + i, true); t = &tns->thumbs[i];
if (t->im != NULL) {
t->x = x + (THUMB_SIZE - t->w) / 2;
t->y = y + (THUMB_SIZE - t->h) / 2;
imlib_context_set_image(t->im);
imlib_render_image_on_drawable_at_size(t->x, t->y, t->w, t->h);
if (tns->files[i].marked)
tns_mark(tns, i, true);
} else {
tns->loadnext = MIN(tns->loadnext, i);
}
if ((i + 1) % tns->cols == 0) { if ((i + 1) % tns->cols == 0) {
x = tns->x; x = tns->x;
y += thumb_dim; y += thumb_dim;
@ -415,7 +447,7 @@ void tns_mark(tns_t *tns, int n, bool mark)
if (tns == NULL || tns->thumbs == NULL || tns->win == NULL) if (tns == NULL || tns->thumbs == NULL || tns->win == NULL)
return; return;
if (n >= 0 && n < tns->cnt) { 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 : win->bgcol;
@ -440,7 +472,7 @@ void tns_highlight(tns_t *tns, int n, bool hl)
if (tns == NULL || tns->thumbs == NULL || tns->win == NULL) if (tns == NULL || tns->thumbs == NULL || tns->win == NULL)
return; return;
if (n >= 0 && n < tns->cnt) { 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; unsigned long col;

View File

@ -31,16 +31,15 @@ typedef struct {
int h; int h;
int x; int x;
int y; int y;
bool loaded;
} thumb_t; } thumb_t;
typedef struct { typedef struct {
const fileinfo_t *files; const fileinfo_t *files;
thumb_t *thumbs; thumb_t *thumbs;
int cap;
int cnt; int cnt;
int loadnext; int loadnext;
int first; int first, end;
int r_first, r_end;
int *sel; int *sel;
win_t *win; win_t *win;
@ -58,6 +57,7 @@ void tns_init(tns_t*, const fileinfo_t*, int, int*, win_t*);
void tns_free(tns_t*); void tns_free(tns_t*);
bool tns_load(tns_t*, int, bool); bool tns_load(tns_t*, int, bool);
void tns_unload(tns_t*, int);
void tns_render(tns_t*); void tns_render(tns_t*);
void tns_mark(tns_t*, int, bool); void tns_mark(tns_t*, int, bool);