From 1d749382f00bb0bfdb900b6ddb0bb8b3743b99d0 Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 19 Aug 2011 15:02:10 +0200 Subject: Put event handling back into main.c; events -> commands --- Makefile | 2 +- commands.c | 400 ++++++++++++++++++++++++++++++++++++++++ commands.h | 63 +++++++ events.c | 601 ------------------------------------------------------------- events.h | 66 ------- main.c | 196 +++++++++++++++++++- types.h | 7 + 7 files changed, 665 insertions(+), 670 deletions(-) create mode 100644 commands.c create mode 100644 commands.h delete mode 100644 events.c delete mode 100644 events.h diff --git a/Makefile b/Makefile index 991d1b4..852a966 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ CFLAGS = -Wall -pedantic -O2 -DVERSION=\"$(VERSION)\" LDFLAGS = LIBS = -lX11 -lImlib2 -SRC = events.o image.c main.c options.c thumbs.c util.c window.c +SRC = commands.c image.c main.c options.c thumbs.c util.c window.c OBJ = $(SRC:.c=.o) sxiv: $(OBJ) diff --git a/commands.c b/commands.c new file mode 100644 index 0000000..7dbd019 --- /dev/null +++ b/commands.c @@ -0,0 +1,400 @@ +/* sxiv: commands.c + * Copyright (c) 2011 Bert Muennich + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include "commands.h" +#include "image.h" +#include "thumbs.h" +#include "types.h" +#include "util.h" + +void cleanup(); +void remove_file(int, unsigned char); +void load_image(int); + +extern appmode_t mode; +extern img_t img; +extern tns_t tns; +extern win_t win; + +extern fileinfo_t *files; +extern int filecnt, fileidx; + +extern int timo_cursor; +extern int timo_redraw; + +int it_quit(arg_t a) { + cleanup(); + exit(0); +} + +int it_switch_mode(arg_t a) { + if (mode == MODE_IMAGE) { + if (!tns.thumbs) + tns_init(&tns, filecnt); + img_close(&img, 0); + win_set_cursor(&win, CURSOR_ARROW); + timo_cursor = 0; + tns.sel = fileidx; + tns.dirty = 1; + mode = MODE_THUMB; + } else { + timo_cursor = TO_CURSOR_HIDE; + load_image(tns.sel); + mode = MODE_IMAGE; + } + return 1; +} + +int it_toggle_fullscreen(arg_t a) { + win_toggle_fullscreen(&win); + if (mode == MODE_IMAGE) + img.checkpan = 1; + else + tns.dirty = 1; + timo_redraw = TO_WIN_RESIZE; + return 0; +} + +int it_reload_image(arg_t a) { + if (mode == MODE_IMAGE) { + load_image(fileidx); + } else if (!tns_load(&tns, tns.sel, &files[tns.sel], True, False)) { + remove_file(tns.sel, 0); + tns.dirty = 1; + if (tns.sel >= tns.cnt) + tns.sel = tns.cnt - 1; + } + return 1; +} + +int it_remove_image(arg_t a) { + if (mode == MODE_IMAGE) { + remove_file(fileidx, 1); + load_image(fileidx >= filecnt ? filecnt - 1 : fileidx); + return 1; + } else if (tns.sel < tns.cnt) { + remove_file(tns.sel, 1); + tns.dirty = 1; + if (tns.sel >= tns.cnt) + tns.sel = tns.cnt - 1; + return 1; + } else { + return 0; + } +} + +int i_navigate(arg_t a) { + int n = (int) a; + + if (mode == MODE_IMAGE) { + n += fileidx; + if (n < 0) + n = 0; + if (n >= filecnt) + n = filecnt - 1; + + if (n != fileidx) { + load_image(n); + return 1; + } + } + return 0; +} + +int it_first(arg_t a) { + if (mode == MODE_IMAGE && fileidx != 0) { + load_image(0); + return 1; + } else if (mode == MODE_THUMB && tns.sel != 0) { + tns.sel = 0; + tns.dirty = 1; + return 1; + } else { + return 0; + } +} + +int it_last(arg_t a) { + if (mode == MODE_IMAGE && fileidx != filecnt - 1) { + load_image(filecnt - 1); + return 1; + } else if (mode == MODE_THUMB && tns.sel != tns.cnt - 1) { + tns.sel = tns.cnt - 1; + tns.dirty = 1; + return 1; + } else { + return 0; + } +} + +int it_move(arg_t a) { + direction_t dir = (direction_t) a; + + if (mode == MODE_IMAGE) + return img_pan(&img, &win, dir, 0); + else + return tns_move_selection(&tns, &win, dir); +} + +int i_pan_screen(arg_t a) { + direction_t dir = (direction_t) a; + + if (mode == MODE_IMAGE) + return img_pan(&img, &win, dir, 1); + else + return 0; +} + +int i_pan_edge(arg_t a) { + direction_t dir = (direction_t) a; + + if (mode == MODE_IMAGE) + return img_pan_edge(&img, &win, dir); + else + return 0; +} + +/* Xlib helper function for i_drag() */ +Bool is_motionnotify(Display *d, XEvent *e, XPointer a) { + return e != NULL && e->type == MotionNotify; +} + +int i_drag(arg_t a) { + int dx = 0, dy = 0, i, ox, oy, x, y; + unsigned int ui; + Bool dragging = True, next = False; + XEvent e; + Window w; + + if (mode != MODE_IMAGE) + return 0; + if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui)) + return 0; + + win_set_cursor(&win, CURSOR_HAND); + + while (dragging) { + if (!next) + XMaskEvent(win.env.dpy, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e); + switch (e.type) { + case ButtonPress: + case ButtonRelease: + dragging = False; + break; + case MotionNotify: + x = e.xmotion.x; + y = e.xmotion.y; + if (x >= 0 && x <= win.w && y >= 0 && y <= win.h) { + dx += x - ox; + dy += y - oy; + } + ox = x; + oy = y; + break; + } + if (dragging) + next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None); + if ((!dragging || !next) && (dx != 0 || dy != 0)) { + if (img_move(&img, &win, dx, dy)) + img_render(&img, &win); + dx = dy = 0; + } + } + + win_set_cursor(&win, CURSOR_ARROW); + timo_cursor = TO_CURSOR_HIDE; + timo_redraw = 0; + + return 0; +} + +int i_zoom(arg_t a) { + int scale = (int) a; + + if (mode != MODE_IMAGE) + return 0; + if (scale > 0) + return img_zoom_in(&img, &win); + else if (scale < 0) + return img_zoom_out(&img, &win); + else + return img_zoom(&img, &win, 1.0); +} + +int i_fit_to_win(arg_t a) { + int ret; + + if (mode == MODE_IMAGE) { + if ((ret = img_fit_win(&img, &win))) + img_center(&img, &win); + return ret; + } else { + return 0; + } +} + +int i_fit_to_img(arg_t a) { + int ret, x, y; + unsigned int w, h; + + if (mode == MODE_IMAGE) { + 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 ((ret = win_moveresize(&win, x, y, w, h))) { + img.x = x - win.x; + img.y = y - win.y; + } + return ret; + } else { + return 0; + } +} + +int i_rotate(arg_t a) { + direction_t dir = (direction_t) a; + + if (mode == MODE_IMAGE) { + if (dir == DIR_LEFT) { + img_rotate_left(&img, &win); + return 1; + } else if (dir == DIR_RIGHT) { + img_rotate_right(&img, &win); + return 1; + } + } + return 0; +} + +int i_toggle_antialias(arg_t a) { + if (mode == MODE_IMAGE) { + img_toggle_antialias(&img); + return 1; + } else { + return 0; + } +} + +int i_toggle_alpha(arg_t a) { + if (mode == MODE_IMAGE) { + img.alpha ^= 1; + return 1; + } else { + return 0; + } +} + +int it_open_with(arg_t a) { + const char *prog = (const char*) a; + pid_t pid; + + if (!prog || !*prog) + return 0; + + if((pid = fork()) == 0) { + execlp(prog, prog, + files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL); + warn("could not exec: %s", prog); + exit(1); + } else if (pid < 0) { + warn("could not for. program was: %s", prog); + } + + return 0; +} + +int it_shell_cmd(arg_t a) { + const char *cline = (const char*) a; + char *cn, *cmdline; + const char *co, *fpath; + int fpcnt, fplen, status; + pid_t pid; + + if (!cline || !*cline) + return 0; + + /* build command line: */ + fpcnt = 0; + co = cline - 1; + while ((co = strchr(co + 1, '#'))) + fpcnt++; + if (!fpcnt) + return 0; + fpath = files[mode == MODE_IMAGE ? fileidx : tns.sel].path; + fplen = strlen(fpath); + cn = cmdline = (char*) s_malloc((strlen(cline) + fpcnt * (fplen + 2)) * + sizeof(char)); + /* replace all '#' with filename: */ + for (co = cline; *co; co++) { + if (*co == '#') { + *cn++ = '"'; + strcpy(cn, fpath); + cn += fplen; + *cn++ = '"'; + } else { + *cn++ = *co; + } + } + *cn = '\0'; + + win_set_cursor(&win, CURSOR_WATCH); + + if ((pid = fork()) == 0) { + execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL); + warn("could not exec: /bin/sh"); + exit(1); + } else if (pid < 0) { + warn("could not fork. command line was: %s", cmdline); + goto end; + } + + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + warn("child exited with non-zero return value: %d. command line was: %s", + WEXITSTATUS(status), cmdline); + + if (mode == MODE_IMAGE) { + if (fileidx < tns.cnt) + tns_load(&tns, fileidx, &files[fileidx], False, True); + img_close(&img, 1); + load_image(fileidx); + } else { + if (!tns_load(&tns, tns.sel, &files[tns.sel], True, False)) { + remove_file(tns.sel, 0); + tns.dirty = 1; + if (tns.sel >= tns.cnt) + tns.sel = tns.cnt - 1; + } + } + +end: + if (mode == MODE_THUMB) + win_set_cursor(&win, CURSOR_ARROW); + /* else: cursor gets reset in redraw() */ + + free(cmdline); + + return 1; +} diff --git a/commands.h b/commands.h new file mode 100644 index 0000000..c249d29 --- /dev/null +++ b/commands.h @@ -0,0 +1,63 @@ +/* sxiv: commands.h + * Copyright (c) 2011 Bert Muennich + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COMMANDS_H +#define COMMANDS_H + +#include + +typedef void* arg_t; +typedef int (*command_f)(arg_t); + +typedef struct { + Bool ctrl; + KeySym ksym; + command_f cmd; + arg_t arg; +} keymap_t; + +typedef struct { + Bool ctrl; + Bool shift; + unsigned int button; + command_f cmd; + arg_t arg; +} button_t; + +int it_quit(arg_t); +int it_switch_mode(arg_t); +int it_toggle_fullscreen(arg_t); +int it_reload_image(arg_t); +int it_remove_image(arg_t); +int i_navigate(arg_t); +int it_first(arg_t); +int it_last(arg_t); +int it_move(arg_t); +int i_pan_screen(arg_t); +int i_pan_edge(arg_t); +int i_drag(arg_t); +int i_zoom(arg_t); +int i_fit_to_win(arg_t); +int i_fit_to_img(arg_t); +int i_rotate(arg_t); +int i_toggle_antialias(arg_t); +int i_toggle_alpha(arg_t); +int it_open_with(arg_t); +int it_shell_cmd(arg_t); + +#endif /* COMMANDS_H */ diff --git a/events.c b/events.c deleted file mode 100644 index 2862d23..0000000 --- a/events.c +++ /dev/null @@ -1,601 +0,0 @@ -/* sxiv: events.c - * Copyright (c) 2011 Bert Muennich - * - * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA. - */ - -#define _GENERAL_CONFIG -#define _MAPPINGS_CONFIG - -#include -#include -#include -#include -#include -#include -#include - -#include "events.h" -#include "image.h" -#include "thumbs.h" -#include "types.h" -#include "util.h" -#include "window.h" -#include "config.h" - -/* timeouts in milliseconds: */ -enum { - TO_WIN_RESIZE = 75, - TO_CURSOR_HIDE = 1500, - TO_THUMBS_LOAD = 200 -}; - -void cleanup(); -void remove_file(int, unsigned char); -void load_image(int); -void update_title(); - -extern appmode_t mode; -extern img_t img; -extern tns_t tns; -extern win_t win; - -extern fileinfo_t *files; -extern int filecnt, fileidx; - -int timo_cursor; -int timo_redraw; - -void redraw() { - if (mode == MODE_IMAGE) { - img_render(&img, &win); - if (timo_cursor) - win_set_cursor(&win, CURSOR_ARROW); - else - win_set_cursor(&win, CURSOR_NONE); - } else { - tns_render(&tns, &win); - } - update_title(); - timo_redraw = 0; -} - -Bool keymask(const keymap_t *k, unsigned int state) { - return (k->ctrl ? ControlMask : 0) == (state & ControlMask); -} - -Bool buttonmask(const button_t *b, unsigned int state) { - return ((b->ctrl ? ControlMask : 0) | (b->shift ? ShiftMask : 0)) == - (state & (ControlMask | ShiftMask)); -} - -void on_keypress(XKeyEvent *kev) { - int i; - KeySym ksym; - char key; - - if (!kev) - return; - - XLookupString(kev, &key, 1, &ksym, NULL); - - for (i = 0; i < LEN(keys); i++) { - if (keys[i].ksym == ksym && keymask(&keys[i], kev->state)) { - if (keys[i].cmd && keys[i].cmd(keys[i].arg)) - redraw(); - return; - } - } -} - -void on_buttonpress(XButtonEvent *bev) { - int i, sel; - - if (!bev) - return; - - if (mode == MODE_IMAGE) { - win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = TO_CURSOR_HIDE; - - for (i = 0; i < LEN(buttons); i++) { - if (buttons[i].button == bev->button && - buttonmask(&buttons[i], bev->state)) - { - if (buttons[i].cmd && buttons[i].cmd(buttons[i].arg)) - redraw(); - return; - } - } - } else { - /* thumbnail mode (hard-coded) */ - switch (bev->button) { - case Button1: - if ((sel = tns_translate(&tns, bev->x, bev->y)) >= 0) { - if (sel == tns.sel) { - load_image(tns.sel); - mode = MODE_IMAGE; - timo_cursor = TO_CURSOR_HIDE; - } else { - tns_highlight(&tns, &win, tns.sel, False); - tns_highlight(&tns, &win, sel, True); - tns.sel = sel; - } - redraw(); - break; - } - break; - case Button4: - case Button5: - if (tns_scroll(&tns, bev->button == Button4 ? DIR_UP : DIR_DOWN)) - redraw(); - break; - } - } -} - -void run() { - int xfd, timeout; - fd_set fds; - struct timeval tt, t0, t1; - XEvent ev; - - timo_cursor = mode == MODE_IMAGE ? TO_CURSOR_HIDE : 0; - - redraw(); - - while (1) { - if (mode == MODE_THUMB && tns.cnt < filecnt) { - /* load thumbnails */ - win_set_cursor(&win, CURSOR_WATCH); - gettimeofday(&t0, 0); - - while (tns.cnt < filecnt && !XPending(win.env.dpy)) { - if (tns_load(&tns, tns.cnt, &files[tns.cnt], False, False)) - tns.cnt++; - else - remove_file(tns.cnt, 0); - gettimeofday(&t1, 0); - if (TIMEDIFF(&t1, &t0) >= TO_THUMBS_LOAD) - break; - } - if (tns.cnt == filecnt) - win_set_cursor(&win, CURSOR_ARROW); - if (!XPending(win.env.dpy)) { - redraw(); - continue; - } else { - timo_redraw = TO_THUMBS_LOAD; - } - } else if (timo_cursor || timo_redraw) { - /* check active timeouts */ - gettimeofday(&t0, 0); - timeout = MIN(timo_cursor + 1, timo_redraw + 1); - MSEC_TO_TIMEVAL(timeout, &tt); - xfd = ConnectionNumber(win.env.dpy); - FD_ZERO(&fds); - FD_SET(xfd, &fds); - - if (!XPending(win.env.dpy)) - select(xfd + 1, &fds, 0, 0, &tt); - gettimeofday(&t1, 0); - timeout = MIN(TIMEDIFF(&t1, &t0), timeout); - - /* timeouts fired? */ - if (timo_cursor) { - timo_cursor = MAX(0, timo_cursor - timeout); - if (!timo_cursor) - win_set_cursor(&win, CURSOR_NONE); - } - if (timo_redraw) { - timo_redraw = MAX(0, timo_redraw - timeout); - if (!timo_redraw) - redraw(); - } - if ((timo_cursor || timo_redraw) && !XPending(win.env.dpy)) - continue; - } - - if (!XNextEvent(win.env.dpy, &ev)) { - /* handle events */ - switch (ev.type) { - case ButtonPress: - on_buttonpress(&ev.xbutton); - break; - case ClientMessage: - if ((Atom) ev.xclient.data.l[0] == wm_delete_win) - return; - break; - case ConfigureNotify: - if (win_configure(&win, &ev.xconfigure)) { - timo_redraw = TO_WIN_RESIZE; - if (mode == MODE_IMAGE) - img.checkpan = 1; - else - tns.dirty = 1; - } - break; - case KeyPress: - on_keypress(&ev.xkey); - break; - case MotionNotify: - if (!timo_cursor) - win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = TO_CURSOR_HIDE; - break; - } - } - } -} - - -/* command functions for key and button mappings: */ - -int it_quit(arg_t a) { - cleanup(); - exit(0); -} - -int it_switch_mode(arg_t a) { - if (mode == MODE_IMAGE) { - if (!tns.thumbs) - tns_init(&tns, filecnt); - img_close(&img, 0); - win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = 0; - tns.sel = fileidx; - tns.dirty = 1; - mode = MODE_THUMB; - } else { - timo_cursor = TO_CURSOR_HIDE; - load_image(tns.sel); - mode = MODE_IMAGE; - } - return 1; -} - -int it_toggle_fullscreen(arg_t a) { - win_toggle_fullscreen(&win); - if (mode == MODE_IMAGE) - img.checkpan = 1; - else - tns.dirty = 1; - timo_redraw = TO_WIN_RESIZE; - return 0; -} - -int it_reload_image(arg_t a) { - if (mode == MODE_IMAGE) { - load_image(fileidx); - } else if (!tns_load(&tns, tns.sel, &files[tns.sel], True, False)) { - remove_file(tns.sel, 0); - tns.dirty = 1; - if (tns.sel >= tns.cnt) - tns.sel = tns.cnt - 1; - } - return 1; -} - -int it_remove_image(arg_t a) { - if (mode == MODE_IMAGE) { - remove_file(fileidx, 1); - load_image(fileidx >= filecnt ? filecnt - 1 : fileidx); - return 1; - } else if (tns.sel < tns.cnt) { - remove_file(tns.sel, 1); - tns.dirty = 1; - if (tns.sel >= tns.cnt) - tns.sel = tns.cnt - 1; - return 1; - } else { - return 0; - } -} - -int i_navigate(arg_t a) { - int n = (int) a; - - if (mode == MODE_IMAGE) { - n += fileidx; - if (n < 0) - n = 0; - if (n >= filecnt) - n = filecnt - 1; - - if (n != fileidx) { - load_image(n); - return 1; - } - } - return 0; -} - -int it_first(arg_t a) { - if (mode == MODE_IMAGE && fileidx != 0) { - load_image(0); - return 1; - } else if (mode == MODE_THUMB && tns.sel != 0) { - tns.sel = 0; - tns.dirty = 1; - return 1; - } else { - return 0; - } -} - -int it_last(arg_t a) { - if (mode == MODE_IMAGE && fileidx != filecnt - 1) { - load_image(filecnt - 1); - return 1; - } else if (mode == MODE_THUMB && tns.sel != tns.cnt - 1) { - tns.sel = tns.cnt - 1; - tns.dirty = 1; - return 1; - } else { - return 0; - } -} - -int it_move(arg_t a) { - direction_t dir = (direction_t) a; - - if (mode == MODE_IMAGE) - return img_pan(&img, &win, dir, 0); - else - return tns_move_selection(&tns, &win, dir); -} - -int i_pan_screen(arg_t a) { - direction_t dir = (direction_t) a; - - if (mode == MODE_IMAGE) - return img_pan(&img, &win, dir, 1); - else - return 0; -} - -int i_pan_edge(arg_t a) { - direction_t dir = (direction_t) a; - - if (mode == MODE_IMAGE) - return img_pan_edge(&img, &win, dir); - else - return 0; -} - -/* Xlib helper function for i_drag() */ -Bool is_motionnotify(Display *d, XEvent *e, XPointer a) { - return e != NULL && e->type == MotionNotify; -} - -int i_drag(arg_t a) { - int dx = 0, dy = 0, i, ox, oy, x, y; - unsigned int ui; - Bool dragging = True, next = False; - XEvent e; - Window w; - - if (mode != MODE_IMAGE) - return 0; - if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui)) - return 0; - - win_set_cursor(&win, CURSOR_HAND); - - while (dragging) { - if (!next) - XMaskEvent(win.env.dpy, - ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e); - switch (e.type) { - case ButtonPress: - case ButtonRelease: - dragging = False; - break; - case MotionNotify: - x = e.xmotion.x; - y = e.xmotion.y; - if (x >= 0 && x <= win.w && y >= 0 && y <= win.h) { - dx += x - ox; - dy += y - oy; - } - ox = x; - oy = y; - break; - } - if (dragging) - next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None); - if ((!dragging || !next) && (dx != 0 || dy != 0)) { - if (img_move(&img, &win, dx, dy)) - img_render(&img, &win); - dx = dy = 0; - } - } - - win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = TO_CURSOR_HIDE; - timo_redraw = 0; - - return 0; -} - -int i_zoom(arg_t a) { - int scale = (int) a; - - if (mode != MODE_IMAGE) - return 0; - if (scale > 0) - return img_zoom_in(&img, &win); - else if (scale < 0) - return img_zoom_out(&img, &win); - else - return img_zoom(&img, &win, 1.0); -} - -int i_fit_to_win(arg_t a) { - int ret; - - if (mode == MODE_IMAGE) { - if ((ret = img_fit_win(&img, &win))) - img_center(&img, &win); - return ret; - } else { - return 0; - } -} - -int i_fit_to_img(arg_t a) { - int ret, x, y; - unsigned int w, h; - - if (mode == MODE_IMAGE) { - 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 ((ret = win_moveresize(&win, x, y, w, h))) { - img.x = x - win.x; - img.y = y - win.y; - } - return ret; - } else { - return 0; - } -} - -int i_rotate(arg_t a) { - direction_t dir = (direction_t) a; - - if (mode == MODE_IMAGE) { - if (dir == DIR_LEFT) { - img_rotate_left(&img, &win); - return 1; - } else if (dir == DIR_RIGHT) { - img_rotate_right(&img, &win); - return 1; - } - } - return 0; -} - -int i_toggle_antialias(arg_t a) { - if (mode == MODE_IMAGE) { - img_toggle_antialias(&img); - return 1; - } else { - return 0; - } -} - -int i_toggle_alpha(arg_t a) { - if (mode == MODE_IMAGE) { - img.alpha ^= 1; - return 1; - } else { - return 0; - } -} - -int it_open_with(arg_t a) { - const char *prog = (const char*) a; - pid_t pid; - - if (!prog || !*prog) - return 0; - - if((pid = fork()) == 0) { - execlp(prog, prog, - files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL); - warn("could not exec: %s", prog); - exit(1); - } else if (pid < 0) { - warn("could not for. program was: %s", prog); - } - - return 0; -} - -int it_shell_cmd(arg_t a) { - const char *cline = (const char*) a; - char *cn, *cmdline; - const char *co, *fpath; - int fpcnt, fplen, status; - pid_t pid; - - if (!cline || !*cline) - return 0; - - /* build command line: */ - fpcnt = 0; - co = cline - 1; - while ((co = strchr(co + 1, '#'))) - fpcnt++; - if (!fpcnt) - return 0; - fpath = files[mode == MODE_IMAGE ? fileidx : tns.sel].path; - fplen = strlen(fpath); - cn = cmdline = (char*) s_malloc((strlen(cline) + fpcnt * (fplen + 2)) * - sizeof(char)); - /* replace all '#' with filename: */ - for (co = cline; *co; co++) { - if (*co == '#') { - *cn++ = '"'; - strcpy(cn, fpath); - cn += fplen; - *cn++ = '"'; - } else { - *cn++ = *co; - } - } - *cn = '\0'; - - win_set_cursor(&win, CURSOR_WATCH); - - if ((pid = fork()) == 0) { - execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL); - warn("could not exec: /bin/sh"); - exit(1); - } else if (pid < 0) { - warn("could not fork. command line was: %s", cmdline); - goto end; - } - - waitpid(pid, &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - warn("child exited with non-zero return value: %d. command line was: %s", - WEXITSTATUS(status), cmdline); - - if (mode == MODE_IMAGE) { - if (fileidx < tns.cnt) - tns_load(&tns, fileidx, &files[fileidx], False, True); - img_close(&img, 1); - load_image(fileidx); - } else { - if (!tns_load(&tns, tns.sel, &files[tns.sel], True, False)) { - remove_file(tns.sel, 0); - tns.dirty = 1; - if (tns.sel >= tns.cnt) - tns.sel = tns.cnt - 1; - } - } - -end: - if (mode == MODE_THUMB) - win_set_cursor(&win, CURSOR_ARROW); - /* else: cursor is reset in redraw() */ - - free(cmdline); - - return 1; -} diff --git a/events.h b/events.h deleted file mode 100644 index 0b48055..0000000 --- a/events.h +++ /dev/null @@ -1,66 +0,0 @@ -/* sxiv: events.h - * Copyright (c) 2011 Bert Muennich - * - * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef EVENTS_H -#define EVENTS_H - -#include - -typedef void* arg_t; -typedef int (*command_f)(arg_t); - -typedef struct { - Bool ctrl; - KeySym ksym; - command_f cmd; - arg_t arg; -} keymap_t; - -typedef struct { - Bool ctrl; - Bool shift; - unsigned int button; - command_f cmd; - arg_t arg; -} button_t; - -void run(); - -/* command functions for key and button mappings: */ -int it_quit(arg_t); -int it_switch_mode(arg_t); -int it_toggle_fullscreen(arg_t); -int it_reload_image(arg_t); -int it_remove_image(arg_t); -int i_navigate(arg_t); -int it_first(arg_t); -int it_last(arg_t); -int it_move(arg_t); -int i_pan_screen(arg_t); -int i_pan_edge(arg_t); -int i_drag(arg_t); -int i_zoom(arg_t); -int i_fit_to_win(arg_t); -int i_fit_to_img(arg_t); -int i_rotate(arg_t); -int i_toggle_antialias(arg_t); -int i_toggle_alpha(arg_t); -int it_open_with(arg_t); -int it_shell_cmd(arg_t); - -#endif /* EVENTS_H */ diff --git a/main.c b/main.c index d8dba0d..44b3e69 100644 --- a/main.c +++ b/main.c @@ -17,11 +17,15 @@ */ #include +#include #include #include #include +#include +#include +#include -#include "events.h" +#include "commands.h" #include "image.h" #include "options.h" #include "thumbs.h" @@ -29,6 +33,9 @@ #include "util.h" #include "window.h" +#define _MAPPINGS_CONFIG +#include "config.h" + enum { TITLE_LEN = 256, FNAME_CNT = 1024 @@ -45,6 +52,9 @@ size_t filesize; char win_title[TITLE_LEN]; +int timo_cursor; +int timo_redraw; + void cleanup() { static int in = 0; @@ -115,7 +125,7 @@ void load_image(int new) { if (new < 0 || new >= filecnt) return; - /* cursor is reset in redraw() */ + /* cursor gets reset in redraw() */ win_set_cursor(&win, CURSOR_WATCH); img_close(&img, 0); @@ -158,6 +168,188 @@ void update_title() { win_set_title(&win, win_title); } +void redraw() { + if (mode == MODE_IMAGE) { + img_render(&img, &win); + if (timo_cursor) + win_set_cursor(&win, CURSOR_ARROW); + else + win_set_cursor(&win, CURSOR_NONE); + } else { + tns_render(&tns, &win); + } + update_title(); + timo_redraw = 0; +} + +Bool keymask(const keymap_t *k, unsigned int state) { + return (k->ctrl ? ControlMask : 0) == (state & ControlMask); +} + +Bool buttonmask(const button_t *b, unsigned int state) { + return ((b->ctrl ? ControlMask : 0) | (b->shift ? ShiftMask : 0)) == + (state & (ControlMask | ShiftMask)); +} + +void on_keypress(XKeyEvent *kev) { + int i; + KeySym ksym; + char key; + + if (!kev) + return; + + XLookupString(kev, &key, 1, &ksym, NULL); + + for (i = 0; i < LEN(keys); i++) { + if (keys[i].ksym == ksym && keymask(&keys[i], kev->state)) { + if (keys[i].cmd && keys[i].cmd(keys[i].arg)) + redraw(); + return; + } + } +} + +void on_buttonpress(XButtonEvent *bev) { + int i, sel; + + if (!bev) + return; + + if (mode == MODE_IMAGE) { + win_set_cursor(&win, CURSOR_ARROW); + timo_cursor = TO_CURSOR_HIDE; + + for (i = 0; i < LEN(buttons); i++) { + if (buttons[i].button == bev->button && + buttonmask(&buttons[i], bev->state)) + { + if (buttons[i].cmd && buttons[i].cmd(buttons[i].arg)) + redraw(); + return; + } + } + } else { + /* thumbnail mode (hard-coded) */ + switch (bev->button) { + case Button1: + if ((sel = tns_translate(&tns, bev->x, bev->y)) >= 0) { + if (sel == tns.sel) { + load_image(tns.sel); + mode = MODE_IMAGE; + timo_cursor = TO_CURSOR_HIDE; + } else { + tns_highlight(&tns, &win, tns.sel, False); + tns_highlight(&tns, &win, sel, True); + tns.sel = sel; + } + redraw(); + break; + } + break; + case Button4: + case Button5: + if (tns_scroll(&tns, bev->button == Button4 ? DIR_UP : DIR_DOWN)) + redraw(); + break; + } + } +} + +void run() { + int xfd, timeout; + fd_set fds; + struct timeval tt, t0, t1; + XEvent ev; + + timo_cursor = mode == MODE_IMAGE ? TO_CURSOR_HIDE : 0; + + redraw(); + + while (1) { + if (mode == MODE_THUMB && tns.cnt < filecnt) { + /* load thumbnails */ + win_set_cursor(&win, CURSOR_WATCH); + gettimeofday(&t0, 0); + + while (tns.cnt < filecnt && !XPending(win.env.dpy)) { + if (tns_load(&tns, tns.cnt, &files[tns.cnt], False, False)) + tns.cnt++; + else + remove_file(tns.cnt, 0); + gettimeofday(&t1, 0); + if (TIMEDIFF(&t1, &t0) >= TO_THUMBS_LOAD) + break; + } + if (tns.cnt == filecnt) + win_set_cursor(&win, CURSOR_ARROW); + if (!XPending(win.env.dpy)) { + redraw(); + continue; + } else { + timo_redraw = TO_THUMBS_LOAD; + } + } else if (timo_cursor || timo_redraw) { + /* check active timeouts */ + gettimeofday(&t0, 0); + timeout = MIN(timo_cursor + 1, timo_redraw + 1); + MSEC_TO_TIMEVAL(timeout, &tt); + xfd = ConnectionNumber(win.env.dpy); + FD_ZERO(&fds); + FD_SET(xfd, &fds); + + if (!XPending(win.env.dpy)) + select(xfd + 1, &fds, 0, 0, &tt); + gettimeofday(&t1, 0); + timeout = MIN(TIMEDIFF(&t1, &t0), timeout); + + /* timeouts fired? */ + if (timo_cursor) { + timo_cursor = MAX(0, timo_cursor - timeout); + if (!timo_cursor) + win_set_cursor(&win, CURSOR_NONE); + } + if (timo_redraw) { + timo_redraw = MAX(0, timo_redraw - timeout); + if (!timo_redraw) + redraw(); + } + if ((timo_cursor || timo_redraw) && !XPending(win.env.dpy)) + continue; + } + + if (!XNextEvent(win.env.dpy, &ev)) { + /* handle events */ + switch (ev.type) { + case ButtonPress: + on_buttonpress(&ev.xbutton); + break; + case ClientMessage: + if ((Atom) ev.xclient.data.l[0] == wm_delete_win) + return; + break; + case ConfigureNotify: + if (win_configure(&win, &ev.xconfigure)) { + timo_redraw = TO_WIN_RESIZE; + if (mode == MODE_IMAGE) + img.checkpan = 1; + else + tns.dirty = 1; + } + break; + case KeyPress: + on_keypress(&ev.xkey); + break; + case MotionNotify: + if (!timo_cursor) + win_set_cursor(&win, CURSOR_ARROW); + timo_cursor = TO_CURSOR_HIDE; + break; + } + } + } +} + int fncmp(const void *a, const void *b) { return strcoll(((fileinfo_t*) a)->name, ((fileinfo_t*) b)->name); } diff --git a/types.h b/types.h index c1bb464..f19d693 100644 --- a/types.h +++ b/types.h @@ -31,4 +31,11 @@ typedef struct { const char *path; /* always absolute */ } fileinfo_t; +/* timeouts in milliseconds: */ +enum { + TO_WIN_RESIZE = 75, + TO_CURSOR_HIDE = 1500, + TO_THUMBS_LOAD = 200 +}; + #endif /* TYPES_H */ -- cgit v1.2.3