aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.h2
-rw-r--r--main.c71
-rw-r--r--options.c12
-rw-r--r--options.h1
-rw-r--r--thumbs.c116
-rw-r--r--thumbs.h50
-rw-r--r--window.c39
-rw-r--r--window.h7
8 files changed, 269 insertions, 29 deletions
diff --git a/config.h b/config.h
index e140446..b53acb4 100644
--- a/config.h
+++ b/config.h
@@ -19,3 +19,5 @@ static const float zoom_levels[] = {
12.5, 25.0, 50.0, 75.0,
100.0, 150.0, 200.0, 400.0, 800.0
};
+
+#define THUMB_SIZE 50
diff --git a/main.c b/main.c
index bbbeb59..80d69b6 100644
--- a/main.c
+++ b/main.c
@@ -29,15 +29,23 @@
#include "image.h"
#include "options.h"
+#include "thumbs.h"
#include "util.h"
#include "window.h"
+typedef enum appmode_e {
+ MODE_NORMAL = 0,
+ MODE_THUMBS
+} appmode_t;
+
void update_title();
int check_append(const char*);
void read_dir_rec(const char*);
void run();
+appmode_t mode;
img_t img;
+tns_t tns;
win_t win;
#define DNAME_CNT 512
@@ -46,6 +54,8 @@ const char **filenames;
int filecnt, fileidx;
size_t filesize;
+int tns_loaded;
+
#define TITLE_LEN 256
char win_title[TITLE_LEN];
@@ -54,6 +64,7 @@ void cleanup() {
if (!in++) {
img_free(&img);
+ tns_free(&tns, &win);
win_close(&win);
}
}
@@ -119,12 +130,21 @@ int main(int argc, char **argv) {
win_open(&win);
img_init(&img, &win);
- load_image();
- img_render(&img, &win);
- update_title();
+ if (options->thumbnails) {
+ tns_loaded = 0;
+ tns_init(&tns, filecnt);
+ }
- run();
+ if (options->thumbnails == 2) {
+ mode = MODE_THUMBS;
+ } else {
+ mode = MODE_NORMAL;
+ load_image();
+ img_render(&img, &win);
+ }
+ update_title();
+ run();
cleanup();
return 0;
@@ -233,6 +253,15 @@ void read_dir_rec(const char *dirname) {
unsigned char timeout;
int mox, moy;
+void redraw() {
+ if (mode == MODE_NORMAL)
+ img_render(&img, &win);
+ else
+ tns_render(&tns, &win);
+ update_title();
+ timeout = 0;
+}
+
void on_keypress(XKeyEvent *kev) {
int x, y;
unsigned int w, h;
@@ -364,11 +393,8 @@ void on_keypress(XKeyEvent *kev) {
break;
}
- if (changed) {
- img_render(&img, &win);
- update_title();
- timeout = 0;
- }
+ if (changed)
+ redraw();
}
void on_buttonpress(XButtonEvent *bev) {
@@ -423,11 +449,8 @@ void on_buttonpress(XButtonEvent *bev) {
break;
}
- if (changed) {
- img_render(&img, &win);
- update_title();
- timeout = 0;
- }
+ if (changed)
+ redraw();
}
void on_motionnotify(XMotionEvent *mev) {
@@ -452,16 +475,27 @@ void run() {
timeout = 0;
while (1) {
- if (timeout) {
+ if (mode == MODE_THUMBS && tns_loaded < filecnt) {
+ win_set_cursor(&win, CURSOR_WATCH);
+ tns_load(&tns, &win, filenames[tns_loaded++]);
+ tns_render(&tns, &win);
+ if (tns_loaded == filecnt)
+ win_set_cursor(&win, CURSOR_ARROW);
+ else if (!XPending(win.env.dpy))
+ continue;
+ } else if (timeout) {
t.tv_sec = 0;
t.tv_usec = 75000;
xfd = ConnectionNumber(win.env.dpy);
FD_ZERO(&fds);
FD_SET(xfd, &fds);
-
+
if (!XPending(win.env.dpy) && !select(xfd + 1, &fds, 0, 0, &t)) {
- img_render(&img, &win);
timeout = 0;
+ if (mode == MODE_NORMAL)
+ img_render(&img, &win);
+ else
+ tns_render(&tns, &win);
}
}
@@ -482,8 +516,9 @@ void run() {
break;
case ConfigureNotify:
if (win_configure(&win, &ev.xconfigure)) {
- img.checkpan = 1;
timeout = 1;
+ if (mode == MODE_NORMAL)
+ img.checkpan = 1;
}
break;
case ClientMessage:
diff --git a/options.c b/options.c
index 286d0b6..ca3be0c 100644
--- a/options.c
+++ b/options.c
@@ -25,12 +25,13 @@
#include "config.h"
#include "options.h"
+#include "util.h"
options_t _options;
const options_t *options = (const options_t*) &_options;
void print_usage() {
- printf("usage: sxiv [-dFfhpqrsvZ] [-g GEOMETRY] [-z ZOOM] FILES...\n");
+ printf("usage: sxiv [-dFfhpqrsTtvZ] [-g GEOMETRY] [-z ZOOM] FILES...\n");
}
void print_version() {
@@ -44,6 +45,7 @@ void parse_options(int argc, char **argv) {
_options.scalemode = SCALE_MODE;
_options.zoom = 1.0;
_options.aa = 1;
+ _options.thumbnails = 0;
_options.fixed = 0;
_options.fullscreen = 0;
@@ -52,7 +54,7 @@ void parse_options(int argc, char **argv) {
_options.quiet = 0;
_options.recursive = 0;
- while ((opt = getopt(argc, argv, "dFfg:hpqrsvZz:")) != -1) {
+ while ((opt = getopt(argc, argv, "dFfg:hpqrsTtvZz:")) != -1) {
switch (opt) {
case '?':
print_usage();
@@ -84,6 +86,12 @@ void parse_options(int argc, char **argv) {
case 's':
_options.scalemode = SCALE_FIT;
break;
+ case 'T':
+ _options.thumbnails = 2;
+ break;
+ case 't':
+ _options.thumbnails = MAX(_options.thumbnails, 1);
+ break;
case 'v':
print_version();
exit(0);
diff --git a/options.h b/options.h
index fd2e0bd..246ddb7 100644
--- a/options.h
+++ b/options.h
@@ -29,6 +29,7 @@ typedef struct options_s {
scalemode_t scalemode;
float zoom;
unsigned char aa;
+ unsigned char thumbnails;
unsigned char fixed;
unsigned char fullscreen;
diff --git a/thumbs.c b/thumbs.c
new file mode 100644
index 0000000..9a8791f
--- /dev/null
+++ b/thumbs.c
@@ -0,0 +1,116 @@
+/* sxiv: thumbs.c
+ * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <Imlib2.h>
+
+#include "config.h"
+#include "thumbs.h"
+#include "util.h"
+
+const int thumb_dim = THUMB_SIZE + 10;
+
+void tns_init(tns_t *tns, int cnt) {
+ if (!tns)
+ return;
+
+ tns->cnt = tns->first = tns->sel = 0;
+ tns->thumbs = (thumb_t*) s_malloc(cnt * sizeof(thumb_t));
+}
+
+void tns_free(tns_t *tns, win_t *win) {
+ int i;
+
+ if (!tns)
+ return;
+
+ for (i = 0; i < tns->cnt; ++i)
+ win_free_pixmap(win, tns->thumbs[i].pm);
+
+ free(tns->thumbs);
+ tns->thumbs = NULL;
+}
+
+void tns_load(tns_t *tns, win_t *win, const char *filename) {
+ int w, h;
+ float z, zw, zh;
+ thumb_t *t;
+ Imlib_Image *im;
+
+ if (!tns || !win || !filename)
+ return;
+
+ if (!(im = imlib_load_image(filename)))
+ return;
+
+ imlib_context_set_image(im);
+
+ w = imlib_image_get_width();
+ h = imlib_image_get_height();
+ zw = (float) THUMB_SIZE / (float) w;
+ zh = (float) THUMB_SIZE / (float) h;
+ z = MIN(zw, zh);
+
+ t = &tns->thumbs[tns->cnt++];
+ t->w = z * w;
+ t->h = z * h;
+
+ t->pm = win_create_pixmap(win, t->w, t->h);
+ imlib_context_set_drawable(t->pm);
+ imlib_render_image_part_on_drawable_at_size(0, 0, w, h,
+ 0, 0, t->w, t->h);
+ imlib_free_image();
+}
+
+void tns_render(tns_t *tns, win_t *win) {
+ int i, cnt, x, y;
+
+ if (!tns || !win)
+ return;
+
+ tns->cols = win->w / thumb_dim;
+ tns->rows = win->h / thumb_dim;
+
+ cnt = tns->cols * tns->rows;
+ if (tns->first && tns->first + cnt > tns->cnt)
+ tns->first = MAX(0, tns->cnt - cnt);
+ cnt = MIN(tns->first + cnt, tns->cnt);
+
+ win_clear(win);
+
+ x = y = 5;
+ i = tns->first;
+
+ while (i < cnt) {
+ tns->thumbs[i].x = x + (THUMB_SIZE - tns->thumbs[i].w) / 2;
+ tns->thumbs[i].y = y + (THUMB_SIZE - tns->thumbs[i].h) / 2;
+ win_draw_pixmap(win, tns->thumbs[i].pm, tns->thumbs[i].x,
+ tns->thumbs[i].y, tns->thumbs[i].w, tns->thumbs[i].h);
+ if (++i % tns->cols == 0) {
+ x = 5;
+ y += thumb_dim;
+ } else {
+ x += thumb_dim;
+ }
+ }
+
+ win_draw(win);
+}
+
diff --git a/thumbs.h b/thumbs.h
new file mode 100644
index 0000000..170be27
--- /dev/null
+++ b/thumbs.h
@@ -0,0 +1,50 @@
+/* sxiv: thumbs.h
+ * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef THUMBS_H
+#define THUMBS_H
+
+#include "window.h"
+
+typedef struct thumb_s {
+ int x;
+ int y;
+ int w;
+ int h;
+ Pixmap pm;
+} thumb_t;
+
+typedef struct tns_s {
+ thumb_t *thumbs;
+ int cnt;
+ int cols;
+ int rows;
+ int first;
+ int sel;
+} tns_t;
+
+extern const int thumb_dim;
+
+void tns_init(tns_t*, int);
+void tns_free(tns_t*, win_t*);
+
+void tns_load(tns_t*, win_t*, const char*);
+
+void tns_render(tns_t*, win_t*);
+
+#endif /* THUMBS_H */
diff --git a/window.c b/window.c
index 76a8e87..35a37fe 100644
--- a/window.c
+++ b/window.c
@@ -26,8 +26,9 @@
#include "util.h"
#include "window.h"
-static Cursor arrow;
-static Cursor hand;
+static Cursor carrow;
+static Cursor chand;
+static Cursor cwatch;
static GC bgc;
Atom wm_delete_win;
@@ -107,8 +108,9 @@ void win_open(win_t *win) {
XSelectInput(e->dpy, win->xwin, StructureNotifyMask | KeyPressMask |
ButtonPressMask | ButtonReleaseMask | Button2MotionMask);
- arrow = XCreateFontCursor(e->dpy, XC_left_ptr);
- hand = XCreateFontCursor(e->dpy, XC_fleur);
+ carrow = XCreateFontCursor(e->dpy, XC_left_ptr);
+ chand = XCreateFontCursor(e->dpy, XC_fleur);
+ cwatch = XCreateFontCursor(e->dpy, XC_watch);
bgc = XCreateGC(e->dpy, win->xwin, 0, None);
@@ -135,8 +137,9 @@ void win_close(win_t *win) {
if (!win)
return;
- XFreeCursor(win->env.dpy, arrow);
- XFreeCursor(win->env.dpy, hand);
+ XFreeCursor(win->env.dpy, carrow);
+ XFreeCursor(win->env.dpy, chand);
+ XFreeCursor(win->env.dpy, cwatch);
XFreeGC(win->env.dpy, bgc);
@@ -211,6 +214,23 @@ void win_toggle_fullscreen(win_t *win) {
SubstructureNotifyMask, &ev);
}
+Pixmap win_create_pixmap(win_t *win, int w, int h) {
+ if (!win)
+ return 0;
+
+ return XCreatePixmap(win->env.dpy, win->xwin, w, h, win->env.depth);
+}
+
+void win_free_pixmap(win_t *win, Pixmap pm) {
+ if (win && pm)
+ XFreePixmap(win->env.dpy, pm);
+}
+
+void win_draw_pixmap(win_t *win, Pixmap pm, int x, int y, int w, int h) {
+ if (win)
+ XCopyArea(win->env.dpy, pm, win->pm, bgc, 0, 0, w, h, x, y);
+}
+
void win_clear(win_t *win) {
win_env_t *e;
XGCValues gcval;
@@ -264,11 +284,14 @@ void win_set_cursor(win_t *win, win_cur_t cursor) {
switch (cursor) {
case CURSOR_HAND:
- XDefineCursor(win->env.dpy, win->xwin, hand);
+ XDefineCursor(win->env.dpy, win->xwin, chand);
+ break;
+ case CURSOR_WATCH:
+ XDefineCursor(win->env.dpy, win->xwin, cwatch);
break;
case CURSOR_ARROW:
default:
- XDefineCursor(win->env.dpy, win->xwin, arrow);
+ XDefineCursor(win->env.dpy, win->xwin, carrow);
break;
}
}
diff --git a/window.h b/window.h
index 1ae431b..f00af22 100644
--- a/window.h
+++ b/window.h
@@ -25,7 +25,8 @@
typedef enum win_cur_e {
CURSOR_ARROW = 0,
- CURSOR_HAND
+ CURSOR_HAND,
+ CURSOR_WATCH
} win_cur_t;
typedef struct win_env_s {
@@ -63,6 +64,10 @@ int win_moveresize(win_t*, int, int, unsigned int, unsigned int);
void win_toggle_fullscreen(win_t*);
+Pixmap win_create_pixmap(win_t*, int, int);
+void win_free_pixmap(win_t*, Pixmap);
+void win_draw_pixmap(win_t*, Pixmap, int, int, int, int);
+
void win_clear(win_t*);
void win_draw(win_t*);