aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile9
-rw-r--r--README.md15
-rw-r--r--TODO3
-rw-r--r--image.c48
-rw-r--r--image.h6
-rw-r--r--main.c20
-rw-r--r--sxiv.190
-rw-r--r--sxiv.h2
-rw-r--r--window.c43
-rw-r--r--window.h4
10 files changed, 219 insertions, 21 deletions
diff --git a/Makefile b/Makefile
index 326ecd4..d144865 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,10 @@
all: sxiv
+VERSION=git-20110126
+
CC?=gcc
PREFIX?=/usr/local
-CFLAGS+= -std=c99 -Wall -pedantic -g
+CFLAGS+= -std=c99 -Wall -pedantic -DVERSION=\"$(VERSION)\"
LDFLAGS+=
LIBS+= -lX11 -lImlib2
@@ -16,7 +18,10 @@ sxiv: $(OBJFILES)
$(CC) $(CFLAGS) -c -o $@ $<
install: all
- install -D -m 4755 -o root -g root sxiv $(PREFIX)/sbin/sxiv
+ install -D -m 4755 -o root -g root sxiv $(PREFIX)/bin/sxiv
+ mkdir -p $(PREFIX)/share/man/man1
+ sed "s/VERSION/$(VERSION)/g" sxiv.1 > $(PREFIX)/share/man/man1/sxiv.1
+ chmod 644 $(PREFIX)/share/man/man1/sxiv.1
clean:
rm -f sxiv *.o
diff --git a/README.md b/README.md
index 7cbc6ce..fced5f8 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,10 @@ sxiv: Simple (or small or suckless) X Image Viewer
sxiv is a really simple alternative to feh and qiv. Its only dependency is
imlib2. The primary goal for writing sxiv is to create an image viewer, which
-only implements the most basic features required for fast image viewing. Its
-code base should be kept small and clean to make it easy for you to dig into it
-and customize it for your needs.
+only implements the most basic features required for fast image viewing. It
+works nicely with tiling window managers and its code base should be kept small
+and clean to make it easy for you to dig into it and customize it for your
+needs.
Installation
------------
@@ -36,8 +37,12 @@ Use the following keys to control sxiv:
Escape Quit sxiv and return an exit value of 2 (useful for scripting)
Space,n Go to the next image
Backspace,p Go to the previous image
- g/G Go to first/last image
- [/] Go 10 images backward/forward
+ g/G Go to first/last image
+ [/] Go 10 images backward/forward
+,= Zoom in
- Zoom out
h,j,k,l Scroll left/down/up/right
+ <,> Rotate image (counter-)clockwise by 90 degrees
+ f Toggle fullscreen mode (requires an EWMH/NetWM compliant
+ window manager)
+ a Toggle anti-aliasing
diff --git a/TODO b/TODO
index 7b87fba..7653411 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,3 @@
- mouse scrolling and zooming
- add some useful command line options
-- write man page
-- toggle aliasing
-- fullscreen mode
- view all images in directories (recursive mode)
diff --git a/image.c b/image.c
index 5187d51..fa2ad5d 100644
--- a/image.c
+++ b/image.c
@@ -33,8 +33,10 @@ void img_init(img_t *img, win_t *win) {
zoom_min = zoom_levels[0] / 100.0;
zoom_max = zoom_levels[zl_cnt - 1] / 100.0;
- if (img)
+ if (img) {
img->zoom = 1.0;
+ img->aa = 1;
+ }
if (win) {
imlib_context_set_display(win->env.dpy);
@@ -63,6 +65,7 @@ int img_load(img_t *img, const char *filename) {
}
imlib_context_set_image(im);
+ imlib_context_set_anti_alias(img->aa);
img->re = 0;
img->checkpan = 0;
@@ -104,7 +107,7 @@ void img_render(img_t *img, win_t *win) {
if (!img || !win || !imlib_context_get_image())
return;
- if ((!img->re || !img->zoomed) && SCALE_MODE != SCALE_ZOOM) {
+ if (!img->zoomed && SCALE_MODE != SCALE_ZOOM) {
/* set zoom level to fit image into window */
zw = (float) win->w / (float) img->w;
zh = (float) win->h / (float) img->h;
@@ -241,3 +244,44 @@ int img_pan(img_t *img, win_t *win, pandir_t dir) {
return ox != img->x || oy != img->y;
}
+
+int img_rotate(img_t *img, win_t *win, int d) {
+ int ox, oy, tmp;
+
+ if (!img || !win)
+ return 0;
+
+ ox = d == 1 ? img->x : win->w - img->x - img->w * img->zoom;
+ oy = d == 3 ? img->y : win->h - img->y - img->h * img->zoom;
+
+ imlib_image_orientate(d);
+
+ img->x = oy + (win->w - win->h) / 2;
+ img->y = ox + (win->h - win->w) / 2;
+
+ tmp = img->w;
+ img->w = img->h;
+ img->h = tmp;
+
+ img->checkpan = 1;
+
+ return 1;
+}
+
+int img_rotate_left(img_t *img, win_t *win) {
+ return img_rotate(img, win, 3);
+}
+
+int img_rotate_right(img_t *img, win_t *win) {
+ return img_rotate(img, win, 1);
+}
+
+int img_toggle_antialias(img_t *img) {
+ if (!img)
+ return 0;
+
+ img->aa ^= 1;
+ imlib_context_set_anti_alias(img->aa);
+
+ return 1;
+}
diff --git a/image.h b/image.h
index 4e4d816..2284dd5 100644
--- a/image.h
+++ b/image.h
@@ -39,6 +39,7 @@ typedef struct img_s {
unsigned char re;
unsigned char checkpan;
unsigned char zoomed;
+ unsigned char aa;
int x;
int y;
int w;
@@ -56,4 +57,9 @@ int img_zoom_out(img_t*);
int img_pan(img_t*, win_t*, pandir_t);
+int img_rotate_left(img_t*, win_t*);
+int img_rotate_right(img_t*, win_t*);
+
+int img_toggle_antialias(img_t*);
+
#endif /* IMAGE_H */
diff --git a/main.c b/main.c
index 2910eb1..ad2d4a4 100644
--- a/main.c
+++ b/main.c
@@ -181,7 +181,7 @@ void on_keypress(XEvent *ev) {
cleanup();
exit(0);
- /* navigate through image list */
+ /* navigate image list */
case 'n':
if (fileidx + 1 < filecnt) {
img_load(&img, filenames[++fileidx]);
@@ -245,6 +245,24 @@ void on_keypress(XEvent *ev) {
case 'l':
changed = img_pan(&img, &win, PAN_RIGHT);
break;
+
+ /* rotation */
+ case '<':
+ changed = img_rotate_left(&img, &win);
+ break;
+ case '>':
+ changed = img_rotate_right(&img, &win);
+ break;
+
+ /* control window */
+ case 'f':
+ win_toggle_fullscreen(&win);
+ break;
+
+ /* miscellaneous */
+ case 'a':
+ changed = img_toggle_antialias(&img);
+ break;
}
if (changed) {
diff --git a/sxiv.1 b/sxiv.1
new file mode 100644
index 0000000..3299cb1
--- /dev/null
+++ b/sxiv.1
@@ -0,0 +1,90 @@
+.TH SXIV 1 sxiv\-VERSION
+.SH NAME
+sxiv \- Simple (or small or suckless) X Image Viewer
+.SH SYNOPSIS
+.B sxiv
+.RB [ \-hv ]
+.IR FILE ...
+.SH DESCRIPTION
+sxiv is a simple image viewer for X. It only has the most basic features
+required for fast image viewing.
+.P
+Please note, that the fullscreen mode requires an EWMH/NetWM compliant window
+manager.
+.SH OPTIONS
+.TP
+.B \-h
+Print brief usage information to standard output and exit.
+.TP
+.B \-v
+Print version information to standard output and exit.
+.SH KEYBOARD COMMANDS
+.SS General
+.TP
+.B q
+Quit sxiv.
+.TP
+.B Escape
+Quit sxiv and return an exit value of 2.
+.SS Navigate image list
+.TP
+.BR Space ", " n
+Go to the next image.
+.TP
+.BR Backspace ", " p
+Go to the previous image.
+.TP
+.B g
+Go to the first image.
+.TP
+.B G
+Go to the last image.
+.TP
+.B [
+Go 10 images backward.
+.TP
+.B ]
+Go 10 images forward.
+.SS Zooming
+.TP
+.BR + ", " =
+Zoom in.
+.TP
+.B \-
+Zoom out.
+.SS Panning
+.TP
+.B h
+Pan left.
+.TP
+.B j
+Pan down.
+.TP
+.B k
+Pan up.
+.TP
+.B l
+Pan right.
+.SS Rotation
+.TP
+.B <
+Rotate image counter-clockwise by 90 degrees.
+.TP
+.B >
+Rotate image clockwise by 90 degrees.
+.SS Control window
+.TP
+.B f
+Toggle fullscreen mode.
+.SS Miscellaneous
+.TP
+.B a
+Toggle anti-aliasing.
+.SH AUTHORS
+.TP
+Bert Muennich <ber.t at gmx.com>
+.SH HOMEPAGE
+.TP
+http://github.com/muennich/sxiv
+.SH SEE ALSO
+.BR feh (1), qiv (1)
diff --git a/sxiv.h b/sxiv.h
index 824cfbb..837ae73 100644
--- a/sxiv.h
+++ b/sxiv.h
@@ -21,8 +21,6 @@
#include "config.h"
-#define VERSION "git-20110123"
-
#define ABS(a) ((a) < 0 ? (-(a)) : (a))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
diff --git a/window.c b/window.c
index 0c6c53a..e1b8ee7 100644
--- a/window.c
+++ b/window.c
@@ -18,17 +18,19 @@
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <X11/Xutil.h>
#include "sxiv.h"
#include "window.h"
+GC bgc;
+
void win_open(win_t *win) {
win_env_t *e;
XClassHint *classhint;
XColor bgcol;
- XGCValues gcval;
if (!win)
return;
@@ -48,6 +50,9 @@ void win_open(win_t *win) {
&bgcol, &bgcol))
DIE("could not allocate color: %s", BG_COLOR);
+ win->bgcol = bgcol.pixel;
+ win->pm = 0;
+
win->w = WIN_WIDTH;
win->h = WIN_HEIGHT;
if (win->w > e->scrw)
@@ -66,9 +71,7 @@ void win_open(win_t *win) {
XSelectInput(e->dpy, win->xwin,
StructureNotifyMask | KeyPressMask | ButtonPressMask);
- gcval.foreground = bgcol.pixel;
- win->bgc = XCreateGC(e->dpy, win->xwin, GCForeground, &gcval);
- win->pm = 0;
+ bgc = XCreateGC(e->dpy, win->xwin, 0, None);
win_set_title(win, "sxiv");
@@ -119,8 +122,34 @@ int win_configure(win_t *win, XConfigureEvent *c) {
return changed;
}
+void win_toggle_fullscreen(win_t *win) {
+ XEvent ev;
+ XClientMessageEvent *cm;
+
+ if (!win)
+ return;
+
+ win->fullscreen ^= 1;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.type = ClientMessage;
+
+ cm = &ev.xclient;
+ cm->window = win->xwin;
+ cm->message_type = XInternAtom(win->env.dpy, "_NET_WM_STATE", False);
+ cm->format = 32;
+ cm->data.l[0] = win->fullscreen;
+ cm->data.l[1] = XInternAtom(win->env.dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ cm->data.l[2] = XInternAtom(win->env.dpy, "_NET_WM_STATE_ABOVE", False);
+ cm->data.l[3] = 0;
+
+ XSendEvent(win->env.dpy, DefaultRootWindow(win->env.dpy), False,
+ SubstructureNotifyMask, &ev);
+}
+
void win_clear(win_t *win) {
win_env_t *e;
+ XGCValues gcval;
if (!win)
return;
@@ -130,7 +159,11 @@ void win_clear(win_t *win) {
if (win->pm)
XFreePixmap(e->dpy, win->pm);
win->pm = XCreatePixmap(e->dpy, win->xwin, e->scrw, e->scrh, e->depth);
- XFillRectangle(e->dpy, win->pm, win->bgc, 0, 0, e->scrw, e->scrh);
+
+ gcval.foreground = win->fullscreen ? BlackPixel(e->dpy, e->scr) : win->bgcol;
+ XChangeGC(e->dpy, bgc, GCForeground, &gcval);
+
+ XFillRectangle(e->dpy, win->pm, bgc, 0, 0, e->scrw, e->scrh);
}
void win_draw(win_t *win) {
diff --git a/window.h b/window.h
index 38d8091..79b5787 100644
--- a/window.h
+++ b/window.h
@@ -33,7 +33,8 @@ typedef struct win_env_s {
typedef struct win_s {
Window xwin;
win_env_t env;
- GC bgc;
+
+ unsigned long bgcol;
Pixmap pm;
int w;
@@ -51,6 +52,7 @@ void win_close(win_t*);
void win_set_title(win_t*, const char*);
int win_configure(win_t*, XConfigureEvent*);
+void win_toggle_fullscreen(win_t*);
void win_clear(win_t*);
void win_draw(win_t*);