aboutsummaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c453
1 files changed, 279 insertions, 174 deletions
diff --git a/main.c b/main.c
index 6828795..c1f2b72 100644
--- a/main.c
+++ b/main.c
@@ -22,6 +22,7 @@
#include <dirent.h>
#include <sys/select.h>
#include <sys/stat.h>
+#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@@ -29,15 +30,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
@@ -54,6 +63,7 @@ void cleanup() {
if (!in++) {
img_free(&img);
+ tns_free(&tns, &win);
win_close(&win);
}
}
@@ -119,12 +129,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_init(&tns, filecnt);
- run();
+ if (options->thumbnails == 2) {
+ mode = MODE_THUMBS;
+ win_clear(&win);
+ win_draw(&win);
+ } else {
+ mode = MODE_NORMAL;
+ load_image();
+ img_render(&img, &win);
+ }
+ update_title();
+ run();
cleanup();
return 0;
@@ -135,15 +154,21 @@ void update_title() {
float size;
const char *unit;
- if (img.valid) {
- size = filesize;
- size_readable(&size, &unit);
- n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] <%d%%> (%.2f%s) %s",
- fileidx + 1, filecnt, (int) (img.zoom * 100.0), size, unit,
- filenames[fileidx]);
+ if (mode == MODE_THUMBS) {
+ n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] %s",
+ tns.cnt ? fileidx + 1 : 0, tns.cnt,
+ tns.cnt ? filenames[fileidx] : "");
} else {
- n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] broken: %s",
- fileidx + 1, filecnt, filenames[fileidx]);
+ if (img.valid) {
+ size = filesize;
+ size_readable(&size, &unit);
+ n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] <%d%%> (%.2f%s) %s",
+ fileidx + 1, filecnt, (int) (img.zoom * 100.0), size, unit,
+ filenames[fileidx]);
+ } else {
+ n = snprintf(win_title, TITLE_LEN, "sxiv: [%d/%d] broken: %s",
+ fileidx + 1, filecnt, filenames[fileidx]);
+ }
}
if (n >= TITLE_LEN) {
@@ -233,6 +258,15 @@ void read_dir_rec(const char *dirname) {
int 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;
@@ -246,6 +280,153 @@ void on_keypress(XKeyEvent *kev) {
XLookupString(kev, &key, 1, &ksym, NULL);
changed = 0;
+ if (mode == MODE_NORMAL) {
+ switch (ksym) {
+ /* navigate image list */
+ case XK_n:
+ case XK_space:
+ if (fileidx + 1 < filecnt) {
+ ++fileidx;
+ changed = load_image();
+ }
+ break;
+ case XK_p:
+ case XK_BackSpace:
+ if (fileidx > 0) {
+ --fileidx;
+ changed = load_image();
+ }
+ break;
+ case XK_bracketleft:
+ if (fileidx != 0) {
+ fileidx = MAX(0, fileidx - 10);
+ changed = load_image();
+ }
+ break;
+ case XK_bracketright:
+ if (fileidx != filecnt - 1) {
+ fileidx = MIN(fileidx + 10, filecnt - 1);
+ changed = load_image();
+ }
+ break;
+ case XK_g:
+ if (fileidx != 0) {
+ fileidx = 0;
+ changed = load_image();
+ }
+ break;
+ case XK_G:
+ if (fileidx != filecnt - 1) {
+ fileidx = filecnt - 1;
+ changed = load_image();
+ }
+ break;
+
+ /* zooming */
+ case XK_plus:
+ case XK_equal:
+ changed = img_zoom_in(&img);
+ break;
+ case XK_minus:
+ changed = img_zoom_out(&img);
+ break;
+ case XK_0:
+ changed = img_zoom(&img, 1.0);
+ break;
+ case XK_w:
+ if ((changed = img_fit_win(&img, &win)))
+ img_center(&img, &win);
+ break;
+
+ /* panning */
+ case XK_h:
+ case XK_Left:
+ changed = img_pan(&img, &win, PAN_LEFT);
+ break;
+ case XK_j:
+ case XK_Down:
+ changed = img_pan(&img, &win, PAN_DOWN);
+ break;
+ case XK_k:
+ case XK_Up:
+ changed = img_pan(&img, &win, PAN_UP);
+ break;
+ case XK_l:
+ case XK_Right:
+ changed = img_pan(&img, &win, PAN_RIGHT);
+ break;
+
+ /* rotation */
+ case XK_less:
+ img_rotate_left(&img, &win);
+ changed = 1;
+ break;
+ case XK_greater:
+ img_rotate_right(&img, &win);
+ changed = 1;
+ break;
+
+ /* control window */
+ case XK_W:
+ x = MAX(0, win.x + img.x);
+ y = MAX(0, win.y + img.y);
+ w = img.w * img.zoom;
+ h = img.h * img.zoom;
+ if ((changed = win_moveresize(&win, x, y, w, h))) {
+ img.x = x - win.x;
+ img.y = y - win.y;
+ }
+ break;
+
+ /* switch to thumnail mode */
+ case XK_Return:
+ if (options->thumbnails) {
+ mode = MODE_THUMBS;
+ changed = tns.dirty = 1;
+ }
+ break;
+
+ /* miscellaneous */
+ case XK_a:
+ img_toggle_antialias(&img);
+ changed = 1;
+ break;
+ case XK_r:
+ changed = load_image();
+ break;
+ }
+ } else {
+ /* thumbnail mode */
+ switch (ksym) {
+ /* open selected image */
+ case XK_Return:
+ load_image();
+ mode = MODE_NORMAL;
+ win_set_cursor(&win, CURSOR_ARROW);
+ changed = 1;
+ break;
+
+ /* move selection */
+ case XK_h:
+ case XK_Left:
+ changed = tns_move_selection(&tns, &win, MOVE_LEFT);
+ break;
+ case XK_j:
+ case XK_Down:
+ changed = tns_move_selection(&tns, &win, MOVE_DOWN);
+ break;
+ case XK_k:
+ case XK_Up:
+ changed = tns_move_selection(&tns, &win, MOVE_UP);
+ break;
+ case XK_l:
+ case XK_Right:
+ changed = tns_move_selection(&tns, &win, MOVE_RIGHT);
+ break;
+ }
+ }
+
+ /* common key mappings */
switch (ksym) {
case XK_Escape:
cleanup();
@@ -253,126 +434,18 @@ void on_keypress(XKeyEvent *kev) {
case XK_q:
cleanup();
exit(0);
-
- /* navigate image list */
- case XK_n:
- case XK_space:
- if (fileidx + 1 < filecnt) {
- ++fileidx;
- changed = load_image();
- }
- break;
- case XK_p:
- case XK_BackSpace:
- if (fileidx > 0) {
- --fileidx;
- changed = load_image();
- }
- break;
- case XK_bracketleft:
- if (fileidx != 0) {
- fileidx = MAX(0, fileidx - 10);
- changed = load_image();
- }
- break;
- case XK_bracketright:
- if (fileidx != filecnt - 1) {
- fileidx = MIN(fileidx + 10, filecnt - 1);
- changed = load_image();
- }
- break;
- case XK_g:
- if (fileidx != 0) {
- fileidx = 0;
- changed = load_image();
- }
- break;
- case XK_G:
- if (fileidx != filecnt - 1) {
- fileidx = filecnt - 1;
- changed = load_image();
- }
- break;
-
- /* zooming */
- case XK_plus:
- case XK_equal:
- changed = img_zoom_in(&img);
- break;
- case XK_minus:
- changed = img_zoom_out(&img);
- break;
- case XK_0:
- changed = img_zoom(&img, 1.0);
- break;
- case XK_w:
- if ((changed = img_fit_win(&img, &win)))
- img_center(&img, &win);
- break;
-
- /* panning */
- case XK_h:
- case XK_Left:
- changed = img_pan(&img, &win, PAN_LEFT);
- break;
- case XK_j:
- case XK_Down:
- changed = img_pan(&img, &win, PAN_DOWN);
- break;
- case XK_k:
- case XK_Up:
- changed = img_pan(&img, &win, PAN_UP);
- break;
- case XK_l:
- case XK_Right:
- changed = img_pan(&img, &win, PAN_RIGHT);
- break;
-
- /* rotation */
- case XK_less:
- img_rotate_left(&img, &win);
- changed = 1;
- break;
- case XK_greater:
- img_rotate_right(&img, &win);
- changed = 1;
- break;
-
- /* control window */
case XK_f:
win_toggle_fullscreen(&win);
/* render on next configurenotify */
break;
- case XK_W:
- x = MAX(0, win.x + img.x);
- y = MAX(0, win.y + img.y);
- w = img.w * img.zoom;
- h = img.h * img.zoom;
- if ((changed = win_moveresize(&win, x, y, w, h))) {
- img.x = x - win.x;
- img.y = y - win.y;
- }
- break;
-
- /* miscellaneous */
- case XK_a:
- img_toggle_antialias(&img);
- changed = 1;
- break;
- case XK_r:
- changed = load_image();
- break;
}
- if (changed) {
- img_render(&img, &win);
- update_title();
- timeout = 0;
- }
+ if (changed)
+ redraw();
}
void on_buttonpress(XButtonEvent *bev) {
- int changed;
+ int changed, sel;
unsigned int mask;
if (!bev)
@@ -381,53 +454,66 @@ void on_buttonpress(XButtonEvent *bev) {
mask = CLEANMASK(bev->state);
changed = 0;
- switch (bev->button) {
- case Button1:
- if (fileidx + 1 < filecnt) {
- ++fileidx;
- changed = load_image();
- }
- break;
- case Button2:
- mox = bev->x;
- moy = bev->y;
- win_set_cursor(&win, CURSOR_HAND);
- break;
- case Button3:
- if (fileidx > 0) {
- --fileidx;
- changed = load_image();
- }
- break;
- case Button4:
- if (mask == ControlMask)
- changed = img_zoom_in(&img);
- else if (mask == ShiftMask)
+ if (mode == MODE_NORMAL) {
+ switch (bev->button) {
+ case Button1:
+ if (fileidx + 1 < filecnt) {
+ ++fileidx;
+ changed = load_image();
+ }
+ break;
+ case Button2:
+ mox = bev->x;
+ moy = bev->y;
+ win_set_cursor(&win, CURSOR_HAND);
+ break;
+ case Button3:
+ if (fileidx > 0) {
+ --fileidx;
+ changed = load_image();
+ }
+ break;
+ case Button4:
+ if (mask == ControlMask)
+ changed = img_zoom_in(&img);
+ else if (mask == ShiftMask)
+ changed = img_pan(&img, &win, PAN_LEFT);
+ else
+ changed = img_pan(&img, &win, PAN_UP);
+ break;
+ case Button5:
+ if (mask == ControlMask)
+ changed = img_zoom_out(&img);
+ else if (mask == ShiftMask)
+ changed = img_pan(&img, &win, PAN_RIGHT);
+ else
+ changed = img_pan(&img, &win, PAN_DOWN);
+ break;
+ case 6:
changed = img_pan(&img, &win, PAN_LEFT);
- else
- changed = img_pan(&img, &win, PAN_UP);
- break;
- case Button5:
- if (mask == ControlMask)
- changed = img_zoom_out(&img);
- else if (mask == ShiftMask)
+ break;
+ case 7:
changed = img_pan(&img, &win, PAN_RIGHT);
- else
- changed = img_pan(&img, &win, PAN_DOWN);
- break;
- case 6:
- changed = img_pan(&img, &win, PAN_LEFT);
- break;
- case 7:
- changed = img_pan(&img, &win, PAN_RIGHT);
- break;
+ break;
+ }
+ } else {
+ /* thumbnail mode */
+ switch (bev->button) {
+ case Button1:
+ if ((sel = tns_translate(&tns, bev->x, bev->y)) >= 0) {
+ fileidx = sel;
+ load_image();
+ mode = MODE_NORMAL;
+ win_set_cursor(&win, CURSOR_ARROW);
+ changed = 1;
+ break;
+ }
+ break;
+ }
}
- if (changed) {
- img_render(&img, &win);
- update_title();
- timeout = 0;
- }
+ if (changed)
+ redraw();
}
void on_motionnotify(XMotionEvent *mev) {
@@ -446,23 +532,39 @@ void on_motionnotify(XMotionEvent *mev) {
void run() {
int xfd;
fd_set fds;
- struct timeval t;
+ struct timeval t, t0;
XEvent ev;
timeout = 0;
while (1) {
- if (timeout) {
+ if (mode == MODE_THUMBS && tns.cnt < filecnt) {
+ win_set_cursor(&win, CURSOR_WATCH);
+ gettimeofday(&t0, 0);
+
+ while (!XPending(win.env.dpy) && tns.cnt < filecnt) {
+ tns_load(&tns, &win, filenames[tns.cnt]);
+ gettimeofday(&t, 0);
+ if (TV_TO_DOUBLE(t) - TV_TO_DOUBLE(t0) >= 0.25)
+ break;
+ }
+ if (tns.cnt == filecnt)
+ win_set_cursor(&win, CURSOR_ARROW);
+ if (!XPending(win.env.dpy)) {
+ redraw();
+ continue;
+ } else {
+ timeout = 75000;
+ }
+ } else if (timeout) {
t.tv_sec = 0;
t.tv_usec = timeout;
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 (!XPending(win.env.dpy) && !select(xfd + 1, &fds, 0, 0, &t))
+ redraw();
}
if (!XNextEvent(win.env.dpy, &ev)) {
@@ -482,8 +584,11 @@ void run() {
break;
case ConfigureNotify:
if (win_configure(&win, &ev.xconfigure)) {
- img.checkpan = 1;
timeout = 75000;
+ if (mode == MODE_NORMAL)
+ img.checkpan = 1;
+ else
+ tns.dirty = 1;
}
break;
case ClientMessage: