Major code refactoring
- Configurable key and mouse mappings in config.h - Put event handling code from main.c into events.[ch]
This commit is contained in:
		
							parent
							
								
									a271e16744
								
							
						
					
					
						commit
						b8ff1677b1
					
				
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| all: sxiv | ||||
| 
 | ||||
| VERSION = git-20110722 | ||||
| VERSION = git-20110726 | ||||
| 
 | ||||
| CC = gcc | ||||
| DESTDIR = | ||||
| @ -9,7 +9,7 @@ CFLAGS = -Wall -pedantic -DVERSION=\"$(VERSION)\" | ||||
| LDFLAGS = | ||||
| LIBS = -lX11 -lImlib2 | ||||
| 
 | ||||
| SRC = image.c main.c options.c thumbs.c util.c window.c | ||||
| SRC = events.o image.c main.c options.c thumbs.c util.c window.c | ||||
| OBJ = $(SRC:.c=.o) | ||||
| 
 | ||||
| sxiv:	$(OBJ) | ||||
|  | ||||
							
								
								
									
										124
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								config.h
									
									
									
									
									
								
							| @ -1,36 +1,120 @@ | ||||
| /* default window dimensions (overwritten via -g option): */ | ||||
| #ifdef _GENERAL_CONFIG | ||||
| 
 | ||||
| /* enable external commands (defined below)? 0 = off, 1 = on:  */ | ||||
| enum { EXT_COMMANDS = 0 }; | ||||
| 
 | ||||
| #endif | ||||
| #ifdef _WINDOW_CONFIG | ||||
| 
 | ||||
| /* default window dimensions (overwritten via -g option):      */ | ||||
| enum { WIN_WIDTH  = 800, WIN_HEIGHT = 600 }; | ||||
| 
 | ||||
| /* default color for window background:                   *
 | ||||
|  * (see X(7) "COLOR NAMES" section for valid values)      */ | ||||
| /* default color for window background:                        *
 | ||||
|  * (see X(7) "COLOR NAMES" section for valid values)           */ | ||||
| static const char * const BG_COLOR  = "#999999"; | ||||
| /* default color for thumbnail selection:                 */ | ||||
| /* default color for thumbnail selection:                      */ | ||||
| static const char * const SEL_COLOR = "#0066FF"; | ||||
| 
 | ||||
| /* how should images be scaled when they are loaded?:     *
 | ||||
|  * (also controllable via -d/-s/-Z/-z options)            * | ||||
|  *   SCALE_DOWN: 100%, but fit large images into window,  * | ||||
|  *   SCALE_FIT:  fit all images into window,              * | ||||
|  *   SCALE_ZOOM: use current zoom level, 100% at startup  */ | ||||
| #endif | ||||
| #ifdef _IMAGE_CONFIG | ||||
| 
 | ||||
| /* how should images be scaled when they are loaded?:          *
 | ||||
|  * (also controllable via -d/-s/-Z/-z options)                 * | ||||
|  *   SCALE_DOWN: 100%, but fit large images into window,       * | ||||
|  *   SCALE_FIT:  fit all images into window,                   * | ||||
|  *   SCALE_ZOOM: use current zoom level, 100% at startup       */ | ||||
| static const scalemode_t SCALE_MODE = SCALE_DOWN; | ||||
| 
 | ||||
| /* levels (percent) to use when zooming via '-' and '+':  */ | ||||
| /* levels (percent) to use when zooming via '-' and '+':       */ | ||||
| static const float zoom_levels[] = { | ||||
| 	 12.5,  25.0,  50.0,  75.0, | ||||
| 	100.0, 150.0, 200.0, 400.0, 800.0 | ||||
| }; | ||||
| 
 | ||||
| /* default dimension of thumbnails (width == height):     */ | ||||
| #endif | ||||
| #ifdef _THUMBS_CONFIG | ||||
| 
 | ||||
| /* default dimension of thumbnails (width == height):          */ | ||||
| enum { THUMB_SIZE = 60 }; | ||||
| 
 | ||||
| /* enable external commands (defined below)? 0=off, 1=on: */ | ||||
| enum { EXT_COMMANDS = 0 }; | ||||
| #endif | ||||
| #ifdef _MAPPINGS_CONFIG | ||||
| 
 | ||||
| /* external commands and corresponding key mappings:      */ | ||||
| static const command_t commands[] = { | ||||
| 	/* ctrl-...  reload?  command, '#' is replaced by filename */ | ||||
| 	{  ',',      1,       "jpegtran -rotate 270 -copy all -outfile # #" }, | ||||
| 	{  '.',      1,       "jpegtran -rotate 90 -copy all -outfile # #" }, | ||||
| 	{  '<',      1,       "mogrify -rotate -90 #" }, | ||||
| 	{  '>',      1,       "mogrify -rotate +90 #" } | ||||
| /* keyboard mappings for image and thumbnail mode:             */ | ||||
| static const keymap_t keys[] = { | ||||
| 	/* key              function            argument */ | ||||
| 	{ XK_q,             quit,               None }, | ||||
| 	{ XK_r,             reload,             None }, | ||||
| 	{ XK_f,             toggle_fullscreen,  None }, | ||||
| 	{ XK_a,             toggle_antialias,   None }, | ||||
| 	{ XK_A,             toggle_alpha,       None }, | ||||
| 	{ XK_Return,        switch_mode,        None }, | ||||
| 
 | ||||
| 	{ XK_g,             first,              None }, | ||||
| 	{ XK_G,             last,               None }, | ||||
| 	{ XK_n,             navigate,           +1 }, | ||||
| 	{ XK_space,         navigate,           +1 }, | ||||
| 	{ XK_p,             navigate,           -1 }, | ||||
| 	{ XK_BackSpace,     navigate,           -1 }, | ||||
| 	{ XK_bracketright,  navigate,           +10 }, | ||||
| 	{ XK_bracketleft,   navigate,           -10 }, | ||||
| 
 | ||||
| 	{ XK_D,             remove_image,       None }, | ||||
| 
 | ||||
| 	{ XK_h,             move,               DIR_LEFT }, | ||||
| 	{ XK_Left,          move,               DIR_LEFT }, | ||||
| 	{ XK_j,             move,               DIR_DOWN }, | ||||
| 	{ XK_Down,          move,               DIR_DOWN }, | ||||
| 	{ XK_k,             move,               DIR_UP }, | ||||
| 	{ XK_Up,            move,               DIR_UP }, | ||||
| 	{ XK_l,             move,               DIR_RIGHT }, | ||||
| 	{ XK_Right,         move,               DIR_RIGHT }, | ||||
| 
 | ||||
| 	{ XK_braceleft,     scroll,             DIR_LEFT }, | ||||
| 	{ XK_Next,          scroll,             DIR_DOWN }, | ||||
| 	{ XK_Prior,         scroll,             DIR_UP }, | ||||
| 	{ XK_braceright,    scroll,             DIR_RIGHT }, | ||||
| 
 | ||||
| 	{ XK_H,             pan_edge,           DIR_LEFT }, | ||||
| 	{ XK_J,             pan_edge,           DIR_DOWN }, | ||||
| 	{ XK_K,             pan_edge,           DIR_UP }, | ||||
| 	{ XK_L,             pan_edge,           DIR_RIGHT }, | ||||
| 
 | ||||
| 	{ XK_plus,          zoom,               +1 }, | ||||
| 	{ XK_equal,         zoom,               +1 }, | ||||
| 	{ XK_KP_Add,        zoom,               +1 }, | ||||
| 	{ XK_minus,         zoom,               -1 }, | ||||
| 	{ XK_KP_Subtract,   zoom,               -1 }, | ||||
| 	{ XK_0,             zoom,               0 }, | ||||
| 	{ XK_KP_0,          zoom,               0 }, | ||||
| 	{ XK_w,             fit_to_win,         None }, | ||||
| 	{ XK_W,             fit_to_img,         None }, | ||||
| 
 | ||||
| 	{ XK_less,          rotate,             DIR_LEFT }, | ||||
| 	{ XK_greater,       rotate,             DIR_RIGHT }, | ||||
| }; | ||||
| 
 | ||||
| /* external commands and corresponding key mappings:           */ | ||||
| static const command_t commands[] = { | ||||
| 	/* ctrl-...    reload?  command, '#' is replaced by filename */ | ||||
| 	{ XK_comma,    True,    "jpegtran -rotate 270 -copy all -outfile # #" }, | ||||
| 	{ XK_period,   True,    "jpegtran -rotate 90 -copy all -outfile # #" }, | ||||
| 	{ XK_less,     True,    "mogrify -rotate -90 #" }, | ||||
| 	{ XK_greater,  True,    "mogrify -rotate +90 #" } | ||||
| }; | ||||
| 
 | ||||
| /* mouse button mappings for image mode:                       */ | ||||
| static const button_t buttons[] = { | ||||
| 	/* modifier     button       function    argument            */ | ||||
| 	{ None,         Button1,     navigate,   +1 }, | ||||
| 	{ None,         Button3,     navigate,   -1 }, | ||||
| 	{ None,         Button2,     drag,       None }, | ||||
| 	{ None,         Button4,     move,       DIR_UP }, | ||||
| 	{ None,         Button5,     move,       DIR_DOWN }, | ||||
| 	{ ShiftMask,    Button4,     move,       DIR_LEFT }, | ||||
| 	{ ShiftMask,    Button5,     move,       DIR_RIGHT }, | ||||
| 	{ ControlMask,  Button4,     zoom,       +1 }, | ||||
| 	{ ControlMask,  Button5,     zoom,       -1 }, | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										562
									
								
								events.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										562
									
								
								events.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,562 @@ | ||||
| /* sxiv: events.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. | ||||
|  */ | ||||
| 
 | ||||
| #define _GENERAL_CONFIG | ||||
| #define _MAPPINGS_CONFIG | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/wait.h> | ||||
| #include <X11/keysym.h> | ||||
| #include <X11/Xutil.h> | ||||
| 
 | ||||
| #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_IMAGE_DRAG  = 1, | ||||
| 	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 char **filenames; | ||||
| extern int filecnt, fileidx; | ||||
| 
 | ||||
| int timo_cursor; | ||||
| int timo_redraw; | ||||
| unsigned char dragging; | ||||
| int mox, moy; | ||||
| 
 | ||||
| int run_command(const char *cline, Bool reload) { | ||||
| 	int fncnt, fnlen; | ||||
| 	char *cn, *cmdline; | ||||
| 	const char *co, *fname; | ||||
| 	pid_t pid; | ||||
| 	int ret, status; | ||||
| 
 | ||||
| 	if (!cline || !*cline) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	fncnt = 0; | ||||
| 	co = cline - 1; | ||||
| 	while ((co = strchr(co + 1, '#'))) | ||||
| 		fncnt++; | ||||
| 
 | ||||
| 	if (!fncnt) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	ret = 0; | ||||
| 	fname = filenames[mode == MODE_NORMAL ? fileidx : tns.sel]; | ||||
| 	fnlen = strlen(fname); | ||||
| 	cn = cmdline = (char*) s_malloc((strlen(cline) + fncnt * (fnlen + 2)) * | ||||
| 	                                sizeof(char)); | ||||
| 
 | ||||
| 	/* replace all '#' with filename */ | ||||
| 	for (co = cline; *co; co++) { | ||||
| 		if (*co == '#') { | ||||
| 			*cn++ = '"'; | ||||
| 			strcpy(cn, fname); | ||||
| 			cn += fnlen; | ||||
| 			*cn++ = '"'; | ||||
| 		} else { | ||||
| 			*cn++ = *co; | ||||
| 		} | ||||
| 	} | ||||
| 	*cn = '\0'; | ||||
| 
 | ||||
| 	if ((pid = fork()) == 0) { | ||||
| 		execlp("/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); | ||||
| 	} else if (reload) { | ||||
| 		waitpid(pid, &status, 0); | ||||
| 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) | ||||
| 			ret = 1; | ||||
| 		else | ||||
| 			warn("child exited with non-zero return value: %d. command line was: %s", | ||||
| 			     WEXITSTATUS(status), cmdline); | ||||
| 	} | ||||
| 	 | ||||
| 	free(cmdline); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| void redraw() { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		img_render(&img, &win); | ||||
| 		if (timo_cursor) | ||||
| 			win_set_cursor(&win, CURSOR_ARROW); | ||||
| 		else if (!dragging) | ||||
| 			win_set_cursor(&win, CURSOR_NONE); | ||||
| 	} else { | ||||
| 		tns_render(&tns, &win); | ||||
| 	} | ||||
| 	update_title(); | ||||
| 	timo_redraw = 0; | ||||
| } | ||||
| 
 | ||||
| void on_keypress(XEvent *ev) { | ||||
| 	int i; | ||||
| 	XKeyEvent *kev; | ||||
| 	KeySym ksym; | ||||
| 	char key; | ||||
| 
 | ||||
| 	if (!ev || ev->type != KeyPress) | ||||
| 		return; | ||||
| 	 | ||||
| 	kev = &ev->xkey; | ||||
| 	XLookupString(kev, &key, 1, &ksym, NULL); | ||||
| 
 | ||||
| 	if (EXT_COMMANDS && (CLEANMASK(kev->state) & ControlMask)) { | ||||
| 		for (i = 0; i < LEN(commands); i++) { | ||||
| 			if (commands[i].ksym == ksym) { | ||||
| 				win_set_cursor(&win, CURSOR_WATCH); | ||||
| 				if (run_command(commands[i].cmdline, commands[i].reload)) { | ||||
| 					if (mode == MODE_NORMAL) { | ||||
| 						if (fileidx < tns.cnt) | ||||
| 							tns_load(&tns, fileidx, filenames[fileidx], 1); | ||||
| 						img_close(&img, 1); | ||||
| 						load_image(fileidx); | ||||
| 					} else { | ||||
| 						if (!tns_load(&tns, tns.sel, filenames[tns.sel], 0)) { | ||||
| 							remove_file(tns.sel, 0); | ||||
| 							tns.dirty = 1; | ||||
| 							if (tns.sel >= tns.cnt) | ||||
| 								tns.sel = tns.cnt - 1; | ||||
| 						} | ||||
| 					} | ||||
| 					redraw(); | ||||
| 				} | ||||
| 				if (mode == MODE_THUMBS) | ||||
| 					win_set_cursor(&win, CURSOR_ARROW); | ||||
| 				else if (!timo_cursor) | ||||
| 					win_set_cursor(&win, CURSOR_NONE); | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < LEN(keys); i++) { | ||||
| 		if (ksym == keys[i].ksym && keys[i].handler) { | ||||
| 			if (keys[i].handler(ev, keys[i].arg)) | ||||
| 				redraw(); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void on_buttonpress(XEvent *ev) { | ||||
| 	int i, sel; | ||||
| 	XButtonEvent *bev; | ||||
| 
 | ||||
| 	if (!ev || ev->type != ButtonPress) | ||||
| 		return; | ||||
| 
 | ||||
| 	bev = &ev->xbutton; | ||||
| 
 | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		if (!dragging) { | ||||
| 			win_set_cursor(&win, CURSOR_ARROW); | ||||
| 			timo_cursor = TO_CURSOR_HIDE; | ||||
| 		} | ||||
| 
 | ||||
| 		for (i = 0; i < LEN(buttons); i++) { | ||||
| 			if (CLEANMASK(bev->state) == CLEANMASK(buttons[i].mod) && | ||||
| 			    bev->button == buttons[i].button && buttons[i].handler) | ||||
| 			{ | ||||
| 				if (buttons[i].handler(ev, buttons[i].arg)) | ||||
| 					redraw(); | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* thumbnail mode */ | ||||
| 		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_NORMAL; | ||||
| 						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 on_motionnotify(XEvent *ev) { | ||||
| 	XMotionEvent *mev; | ||||
| 
 | ||||
| 	if (!ev || ev->type != MotionNotify) | ||||
| 		return; | ||||
| 
 | ||||
| 	mev = &ev->xmotion; | ||||
| 
 | ||||
| 	if (mev->x >= 0 && mev->x <= win.w && mev->y >= 0 && mev->y <= win.h) { | ||||
| 		if (img_move(&img, &win, mev->x - mox, mev->y - moy)) | ||||
| 			timo_redraw = TO_IMAGE_DRAG; | ||||
| 		mox = mev->x; | ||||
| 		moy = mev->y; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void run() { | ||||
| 	int xfd, timeout; | ||||
| 	fd_set fds; | ||||
| 	struct timeval tt, t0, t1; | ||||
| 	XEvent ev; | ||||
| 
 | ||||
| 	dragging = 0; | ||||
| 	timo_cursor = mode == MODE_NORMAL ? TO_CURSOR_HIDE : 0; | ||||
| 
 | ||||
| 	redraw(); | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		if (mode == MODE_THUMBS && 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, filenames[tns.cnt], 0)) | ||||
| 					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)) { | ||||
| 			switch (ev.type) { | ||||
| 				case ButtonPress: | ||||
| 					on_buttonpress(&ev); | ||||
| 					break; | ||||
| 				case ButtonRelease: | ||||
| 					if (dragging) { | ||||
| 						dragging = 0; | ||||
| 						if (mode == MODE_NORMAL) { | ||||
| 							win_set_cursor(&win, CURSOR_ARROW); | ||||
| 							timo_cursor = TO_CURSOR_HIDE; | ||||
| 						} | ||||
| 					} | ||||
| 					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_NORMAL) | ||||
| 							img.checkpan = 1; | ||||
| 						else | ||||
| 							tns.dirty = 1; | ||||
| 					} | ||||
| 					break; | ||||
| 				case KeyPress: | ||||
| 					on_keypress(&ev); | ||||
| 					break; | ||||
| 				case MotionNotify: | ||||
| 					if (dragging) { | ||||
| 						on_motionnotify(&ev); | ||||
| 					} else if (mode == MODE_NORMAL) { | ||||
| 						if (!timo_cursor) | ||||
| 							win_set_cursor(&win, CURSOR_ARROW); | ||||
| 						timo_cursor = TO_CURSOR_HIDE; | ||||
| 					} | ||||
| 					break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* handler functions for key and button mappings: */ | ||||
| 
 | ||||
| int quit(XEvent *e, arg_t a) { | ||||
| 	cleanup(); | ||||
| 	exit(0); | ||||
| } | ||||
| 
 | ||||
| int reload(XEvent *e, arg_t a) { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		load_image(fileidx); | ||||
| 		return 1; | ||||
| 	} else { | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int toggle_fullscreen(XEvent *e, arg_t a) { | ||||
| 	win_toggle_fullscreen(&win); | ||||
| 	if (mode == MODE_NORMAL) | ||||
| 		img.checkpan = 1; | ||||
| 	else | ||||
| 		tns.dirty = 1; | ||||
| 	timo_redraw = TO_WIN_RESIZE; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int toggle_antialias(XEvent *e, arg_t a) { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		img_toggle_antialias(&img); | ||||
| 		return 1; | ||||
| 	} else { | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int toggle_alpha(XEvent *e, arg_t a) { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		img.alpha ^= 1; | ||||
| 		return 1; | ||||
| 	} else { | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int switch_mode(XEvent *e, arg_t a) { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		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_THUMBS; | ||||
| 	} else { | ||||
| 		timo_cursor = TO_CURSOR_HIDE; | ||||
| 		load_image(tns.sel); | ||||
| 		mode = MODE_NORMAL; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| int navigate(XEvent *e, arg_t n) { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		n += fileidx; | ||||
| 		if (n < 0) | ||||
| 			n = 0; | ||||
| 		if (n >= filecnt) | ||||
| 			n = filecnt - 1; | ||||
| 
 | ||||
| 		if (n != fileidx) { | ||||
| 			load_image(n); | ||||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int first(XEvent *e, arg_t a) { | ||||
| 	if (mode == MODE_NORMAL && fileidx != 0) { | ||||
| 		load_image(0); | ||||
| 		return 1; | ||||
| 	} else if (mode == MODE_THUMBS && tns.sel != 0) { | ||||
| 		tns.sel = 0; | ||||
| 		tns.dirty = 1; | ||||
| 		return 1; | ||||
| 	} else { | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int last(XEvent *e, arg_t a) { | ||||
| 	if (mode == MODE_NORMAL && fileidx != filecnt - 1) { | ||||
| 		load_image(filecnt - 1); | ||||
| 		return 1; | ||||
| 	} else if (mode == MODE_THUMBS && tns.sel != tns.cnt - 1) { | ||||
| 		tns.sel = tns.cnt - 1; | ||||
| 		tns.dirty = 1; | ||||
| 		return 1; | ||||
| 	} else { | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int remove_image(XEvent *e, arg_t a) { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		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 move(XEvent *e, arg_t dir) { | ||||
| 	if (mode == MODE_NORMAL) | ||||
| 		return img_pan(&img, &win, dir, 0); | ||||
| 	else | ||||
| 		return tns_move_selection(&tns, &win, dir); | ||||
| } | ||||
| 
 | ||||
| int scroll(XEvent *e, arg_t dir) { | ||||
| 	if (mode == MODE_NORMAL) | ||||
| 		return img_pan(&img, &win, dir, 1); | ||||
| 	else | ||||
| 		return 0; | ||||
| } | ||||
| 
 | ||||
| int pan_edge(XEvent *e, arg_t dir) { | ||||
| 	if (mode == MODE_NORMAL) | ||||
| 		return img_pan_edge(&img, &win, dir); | ||||
| 	else | ||||
| 		return 0; | ||||
| } | ||||
| 
 | ||||
| int drag(XEvent *e, arg_t a) { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		mox = e->xbutton.x; | ||||
| 		moy = e->xbutton.y; | ||||
| 		win_set_cursor(&win, CURSOR_HAND); | ||||
| 		timo_cursor = 0; | ||||
| 		dragging = 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int rotate(XEvent *e, arg_t dir) { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		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 zoom(XEvent *e, arg_t scale) { | ||||
| 	if (mode != MODE_NORMAL) | ||||
| 		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 fit_to_win(XEvent *e, arg_t ret) { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		if ((ret = img_fit_win(&img, &win))) | ||||
| 			img_center(&img, &win); | ||||
| 		return ret; | ||||
| 	} else { | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int fit_to_img(XEvent *e, arg_t ret) { | ||||
| 	int x, y; | ||||
| 	unsigned int w, h; | ||||
| 
 | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		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; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										67
									
								
								events.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								events.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| /* sxiv: events.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 EVENTS_H | ||||
| #define EVENTS_H | ||||
| 
 | ||||
| #include <X11/Xlib.h> | ||||
| 
 | ||||
| typedef struct { | ||||
| 	KeySym ksym; | ||||
| 	Bool reload; | ||||
| 	const char *cmdline; | ||||
| } command_t; | ||||
| 
 | ||||
| typedef int arg_t; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	KeySym ksym; | ||||
| 	int (*handler)(XEvent*, arg_t); | ||||
| 	arg_t arg; | ||||
| } keymap_t; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	unsigned int mod; | ||||
| 	unsigned int button; | ||||
| 	int (*handler)(XEvent*, arg_t); | ||||
| 	arg_t arg; | ||||
| } button_t; | ||||
| 
 | ||||
| void run(); | ||||
| 
 | ||||
| /* handler functions for key and button mappings: */ | ||||
| int quit(XEvent*, arg_t); | ||||
| int reload(XEvent*, arg_t); | ||||
| int toggle_fullscreen(XEvent*, arg_t); | ||||
| int toggle_antialias(XEvent*, arg_t); | ||||
| int toggle_alpha(XEvent*, arg_t); | ||||
| int switch_mode(XEvent*, arg_t); | ||||
| int navigate(XEvent*, arg_t); | ||||
| int first(XEvent*, arg_t); | ||||
| int last(XEvent*, arg_t); | ||||
| int remove_image(XEvent*, arg_t); | ||||
| int move(XEvent*, arg_t); | ||||
| int scroll(XEvent*, arg_t); | ||||
| int pan_edge(XEvent*, arg_t); | ||||
| int drag(XEvent*, arg_t); | ||||
| int rotate(XEvent*, arg_t); | ||||
| int zoom(XEvent*, arg_t); | ||||
| int fit_to_win(XEvent*, arg_t); | ||||
| int fit_to_img(XEvent*, arg_t); | ||||
| 
 | ||||
| #endif /* EVENTS_H */ | ||||
							
								
								
									
										6
									
								
								image.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								image.c
									
									
									
									
									
								
							| @ -16,6 +16,8 @@ | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
|  */ | ||||
| 
 | ||||
| #define _IMAGE_CONFIG | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include "image.h" | ||||
| @ -238,7 +240,7 @@ int img_zoom_in(img_t *img, win_t *win) { | ||||
| 	if (!img || !img->im || !win) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	for (i = 1; i < zl_cnt; ++i) { | ||||
| 	for (i = 1; i < zl_cnt; i++) { | ||||
| 		if (zoom_levels[i] > img->zoom * 100.0) | ||||
| 			return img_zoom(img, win, zoom_levels[i] / 100.0); | ||||
| 	} | ||||
| @ -251,7 +253,7 @@ int img_zoom_out(img_t *img, win_t *win) { | ||||
| 	if (!img || !img->im || !win) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	for (i = zl_cnt - 2; i >= 0; --i) { | ||||
| 	for (i = zl_cnt - 2; i >= 0; i--) { | ||||
| 		if (zoom_levels[i] < img->zoom * 100.0) | ||||
| 			return img_zoom(img, win, zoom_levels[i] / 100.0); | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										648
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										648
									
								
								main.c
									
									
									
									
									
								
							| @ -16,32 +16,22 @@ | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
|  */ | ||||
| 
 | ||||
| #define _XOPEN_SOURCE 700 | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <sys/select.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/stat.h> | ||||
| 
 | ||||
| #include <X11/Xlib.h> | ||||
| #include <X11/Xutil.h> | ||||
| #include <X11/keysym.h> | ||||
| 
 | ||||
| #include "events.h" | ||||
| #include "image.h" | ||||
| #include "options.h" | ||||
| #include "thumbs.h" | ||||
| #include "types.h" | ||||
| #include "util.h" | ||||
| #include "window.h" | ||||
| #include "config.h" | ||||
| 
 | ||||
| enum { TITLE_LEN = 256, FNAME_CNT = 1024 }; | ||||
| 
 | ||||
| void run(); | ||||
| enum { | ||||
| 	TITLE_LEN = 256, | ||||
| 	FNAME_CNT = 1024 | ||||
| }; | ||||
| 
 | ||||
| appmode_t mode; | ||||
| img_t img; | ||||
| @ -64,6 +54,23 @@ void cleanup() { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int check_add_file(char *filename) { | ||||
| 	if (!filename) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (access(filename, R_OK)) { | ||||
| 		warn("could not open file: %s", filename); | ||||
| 		return 0; | ||||
| 	} else { | ||||
| 		if (fileidx == filecnt) { | ||||
| 			filecnt *= 2; | ||||
| 			filenames = (char**) s_realloc(filenames, filecnt * sizeof(char*)); | ||||
| 		} | ||||
| 		filenames[fileidx++] = filename; | ||||
| 		return 1; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void remove_file(int n, unsigned char silent) { | ||||
| 	if (n < 0 || n >= filecnt) | ||||
| 		return; | ||||
| @ -84,32 +91,32 @@ void remove_file(int n, unsigned char silent) { | ||||
| 		memset(tns.thumbs + tns.cnt - 1, 0, sizeof(thumb_t)); | ||||
| 	} | ||||
| 
 | ||||
| 	--filecnt; | ||||
| 	filecnt--; | ||||
| 	if (n < tns.cnt) | ||||
| 		--tns.cnt; | ||||
| 		tns.cnt--; | ||||
| } | ||||
| 
 | ||||
| int load_image(int new) { | ||||
| void load_image(int new) { | ||||
| 	struct stat fstats; | ||||
| 
 | ||||
| 	if (new >= 0 && new < filecnt) { | ||||
| 		win_set_cursor(&win, CURSOR_WATCH); | ||||
| 		img_close(&img, 0); | ||||
| 	if (new < 0 || new >= filecnt) | ||||
| 		return; | ||||
| 
 | ||||
| 		while (!img_load(&img, filenames[new])) { | ||||
| 			remove_file(new, 0); | ||||
| 			if (new >= filecnt) | ||||
| 				new = filecnt - 1; | ||||
| 		} | ||||
| 		fileidx = new; | ||||
| 		if (!stat(filenames[new], &fstats)) | ||||
| 			filesize = fstats.st_size; | ||||
| 		else | ||||
| 			filesize = 0; | ||||
| 	/* cursor is reset in redraw() */ | ||||
| 	win_set_cursor(&win, CURSOR_WATCH); | ||||
| 	img_close(&img, 0); | ||||
| 		 | ||||
| 		/* cursor is reset in redraw() */ | ||||
| 	while (!img_load(&img, filenames[new])) { | ||||
| 		remove_file(new, 0); | ||||
| 		if (new >= filecnt) | ||||
| 			new = filecnt - 1; | ||||
| 	} | ||||
| 	return 1; | ||||
| 
 | ||||
| 	fileidx = new; | ||||
| 	if (!stat(filenames[new], &fstats)) | ||||
| 		filesize = fstats.st_size; | ||||
| 	else | ||||
| 		filesize = 0; | ||||
| } | ||||
| 
 | ||||
| void update_title() { | ||||
| @ -138,23 +145,6 @@ void update_title() { | ||||
| 	win_set_title(&win, win_title); | ||||
| } | ||||
| 
 | ||||
| int check_append(char *filename) { | ||||
| 	if (!filename) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (access(filename, R_OK)) { | ||||
| 		warn("could not open file: %s", filename); | ||||
| 		return 0; | ||||
| 	} else { | ||||
| 		if (fileidx == filecnt) { | ||||
| 			filecnt *= 2; | ||||
| 			filenames = (char**) s_realloc(filenames, filecnt * sizeof(char*)); | ||||
| 		} | ||||
| 		filenames[fileidx++] = filename; | ||||
| 		return 1; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int fncmp(const void *a, const void *b) { | ||||
| 	return strcoll(*((char* const*) a), *((char* const*) b)); | ||||
| } | ||||
| @ -187,20 +177,21 @@ int main(int argc, char **argv) { | ||||
| 	filenames = (char**) s_malloc(filecnt * sizeof(char*)); | ||||
| 	fileidx = 0; | ||||
| 
 | ||||
| 	/* build file list: */ | ||||
| 	if (options->from_stdin) { | ||||
| 		while ((len = getline(&filename, &n, stdin)) > 0) { | ||||
| 			if (filename[len-1] == '\n') | ||||
| 				filename[len-1] = '\0'; | ||||
| 			if (!*filename || !check_append(filename)) | ||||
| 			if (!*filename || !check_add_file(filename)) | ||||
| 				free(filename); | ||||
| 			filename = NULL; | ||||
| 		} | ||||
| 	} else { | ||||
| 		for (i = 0; i < options->filecnt; ++i) { | ||||
| 		for (i = 0; i < options->filecnt; i++) { | ||||
| 			filename = options->filenames[i]; | ||||
| 
 | ||||
| 			if (stat(filename, &fstats) || !S_ISDIR(fstats.st_mode)) { | ||||
| 				check_append(filename); | ||||
| 				check_add_file(filename); | ||||
| 			} else { | ||||
| 				if (!options->recursive) { | ||||
| 					warn("ignoring directory: %s", filename); | ||||
| @ -212,7 +203,7 @@ int main(int argc, char **argv) { | ||||
| 				} | ||||
| 				start = fileidx; | ||||
| 				while ((filename = r_readdir(&dir))) { | ||||
| 					if (!check_append(filename)) | ||||
| 					if (!check_add_file(filename)) | ||||
| 						free((void*) filename); | ||||
| 				} | ||||
| 				r_closedir(&dir); | ||||
| @ -252,550 +243,3 @@ int main(int argc, char **argv) { | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int run_command(const char *cline, Bool reload) { | ||||
| 	int fncnt, fnlen; | ||||
| 	char *cn, *cmdline; | ||||
| 	const char *co, *fname; | ||||
| 	pid_t pid; | ||||
| 	int ret, status; | ||||
| 
 | ||||
| 	if (!cline || !*cline) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	fncnt = 0; | ||||
| 	co = cline - 1; | ||||
| 	while ((co = strchr(co + 1, '#'))) | ||||
| 		++fncnt; | ||||
| 
 | ||||
| 	if (!fncnt) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	ret = 0; | ||||
| 	fname = filenames[mode == MODE_NORMAL ? fileidx : tns.sel]; | ||||
| 	fnlen = strlen(fname); | ||||
| 	cn = cmdline = (char*) s_malloc((strlen(cline) + fncnt * (fnlen + 2)) * | ||||
| 	                                sizeof(char)); | ||||
| 
 | ||||
| 	/* replace all '#' with filename */ | ||||
| 	for (co = cline; *co; ++co) { | ||||
| 		if (*co == '#') { | ||||
| 			*cn++ = '"'; | ||||
| 			strcpy(cn, fname); | ||||
| 			cn += fnlen; | ||||
| 			*cn++ = '"'; | ||||
| 		} else { | ||||
| 			*cn++ = *co; | ||||
| 		} | ||||
| 	} | ||||
| 	*cn = '\0'; | ||||
| 
 | ||||
| 	if ((pid = fork()) == 0) { | ||||
| 		execlp("/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); | ||||
| 	} else if (reload) { | ||||
| 		waitpid(pid, &status, 0); | ||||
| 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) | ||||
| 			ret = 1; | ||||
| 		else | ||||
| 			warn("child exited with non-zero return value: %d. command line was: %s", | ||||
| 			     WEXITSTATUS(status), cmdline); | ||||
| 	} | ||||
| 	 | ||||
| 	free(cmdline); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* event handling */ | ||||
| 
 | ||||
| /* timeouts in milliseconds: */ | ||||
| enum { | ||||
| 	TO_WIN_RESIZE  = 75, | ||||
| 	TO_IMAGE_DRAG  = 1, | ||||
| 	TO_CURSOR_HIDE = 1500, | ||||
| 	TO_THUMBS_LOAD = 200 | ||||
| }; | ||||
| 
 | ||||
| int timo_cursor; | ||||
| int timo_redraw; | ||||
| unsigned char drag; | ||||
| int mox, moy; | ||||
| 
 | ||||
| void redraw() { | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		img_render(&img, &win); | ||||
| 		if (timo_cursor) | ||||
| 			win_set_cursor(&win, CURSOR_ARROW); | ||||
| 		else if (!drag) | ||||
| 			win_set_cursor(&win, CURSOR_NONE); | ||||
| 	} else { | ||||
| 		tns_render(&tns, &win); | ||||
| 	} | ||||
| 	update_title(); | ||||
| 	timo_redraw = 0; | ||||
| } | ||||
| 
 | ||||
| void on_keypress(XKeyEvent *kev) { | ||||
| 	int x, y; | ||||
| 	unsigned int w, h; | ||||
| 	char key; | ||||
| 	KeySym ksym; | ||||
| 	int changed, ctrl; | ||||
| 
 | ||||
| 	if (!kev) | ||||
| 		return; | ||||
| 	 | ||||
| 	XLookupString(kev, &key, 1, &ksym, NULL); | ||||
| 	changed = 0; | ||||
| 	ctrl = CLEANMASK(kev->state) & ControlMask; | ||||
| 
 | ||||
| 	/* external commands from commands.h */ | ||||
| 	if (EXT_COMMANDS && ctrl) { | ||||
| 		for (x = 0; x < LEN(commands); ++x) { | ||||
| 			if (commands[x].key == key) { | ||||
| 				win_set_cursor(&win, CURSOR_WATCH); | ||||
| 				if (run_command(commands[x].cmdline, commands[x].reload)) { | ||||
| 					if (mode == MODE_NORMAL) { | ||||
| 						if (fileidx < tns.cnt) | ||||
| 							tns_load(&tns, fileidx, filenames[fileidx], 1); | ||||
| 						img_close(&img, 1); | ||||
| 						load_image(fileidx); | ||||
| 					} else { | ||||
| 						if (!tns_load(&tns, tns.sel, filenames[tns.sel], 0)) { | ||||
| 							remove_file(tns.sel, 0); | ||||
| 							tns.dirty = 1; | ||||
| 							if (tns.sel >= tns.cnt) | ||||
| 								tns.sel = tns.cnt - 1; | ||||
| 						} | ||||
| 					} | ||||
| 					redraw(); | ||||
| 				} | ||||
| 				if (mode == MODE_THUMBS) | ||||
| 					win_set_cursor(&win, CURSOR_ARROW); | ||||
| 				else if (!timo_cursor) | ||||
| 					win_set_cursor(&win, CURSOR_NONE); | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		switch (ksym) { | ||||
| 			/* navigate image list */ | ||||
| 			case XK_n: | ||||
| 			case XK_space: | ||||
| 				if (fileidx + 1 < filecnt) | ||||
| 					changed = load_image(fileidx + 1); | ||||
| 				break; | ||||
| 			case XK_p: | ||||
| 			case XK_BackSpace: | ||||
| 				if (fileidx > 0) | ||||
| 					changed = load_image(fileidx - 1); | ||||
| 				break; | ||||
| 			case XK_bracketleft: | ||||
| 				if (fileidx != 0) | ||||
| 					changed = load_image(MAX(0, fileidx - 10)); | ||||
| 				break; | ||||
| 			case XK_bracketright: | ||||
| 				if (fileidx != filecnt - 1) | ||||
| 					changed = load_image(MIN(fileidx + 10, filecnt - 1)); | ||||
| 				break; | ||||
| 			case XK_g: | ||||
| 				if (fileidx != 0) | ||||
| 					changed = load_image(0); | ||||
| 				break; | ||||
| 			case XK_G: | ||||
| 				if (fileidx != filecnt - 1) | ||||
| 					changed = load_image(filecnt - 1); | ||||
| 				break; | ||||
| 
 | ||||
| 			/* zooming */ | ||||
| 			case XK_plus: | ||||
| 			case XK_equal: | ||||
| 			case XK_KP_Add: | ||||
| 				changed = img_zoom_in(&img, &win); | ||||
| 				break; | ||||
| 			case XK_minus: | ||||
| 			case XK_KP_Subtract: | ||||
| 				changed = img_zoom_out(&img, &win); | ||||
| 				break; | ||||
| 			case XK_0: | ||||
| 			case XK_KP_0: | ||||
| 				changed = img_zoom(&img, &win, 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, DIR_LEFT, ctrl); | ||||
| 				break; | ||||
| 			case XK_j: | ||||
| 			case XK_Down: | ||||
| 				changed = img_pan(&img, &win, DIR_DOWN, ctrl); | ||||
| 				break; | ||||
| 			case XK_k: | ||||
| 			case XK_Up: | ||||
| 				changed = img_pan(&img, &win, DIR_UP, ctrl); | ||||
| 				break; | ||||
| 			case XK_l: | ||||
| 			case XK_Right: | ||||
| 				changed = img_pan(&img, &win, DIR_RIGHT, ctrl); | ||||
| 				break; | ||||
| 			case XK_Prior: | ||||
| 				changed = img_pan(&img, &win, DIR_UP, 1); | ||||
| 				break; | ||||
| 			case XK_Next: | ||||
| 				changed = img_pan(&img, &win, DIR_DOWN, 1); | ||||
| 				break; | ||||
| 
 | ||||
| 			case XK_H: | ||||
| 				changed = img_pan_edge(&img, &win, DIR_LEFT); | ||||
| 				break; | ||||
| 			case XK_J: | ||||
| 				changed = img_pan_edge(&img, &win, DIR_DOWN); | ||||
| 				break; | ||||
| 			case XK_K: | ||||
| 				changed = img_pan_edge(&img, &win, DIR_UP); | ||||
| 				break; | ||||
| 			case XK_L: | ||||
| 				changed = img_pan_edge(&img, &win, DIR_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 thumbnail mode */ | ||||
| 			case XK_Return: | ||||
| 				if (!tns.thumbs) | ||||
| 					tns_init(&tns, filecnt); | ||||
| 				img_close(&img, 0); | ||||
| 				mode = MODE_THUMBS; | ||||
| 				win_set_cursor(&win, CURSOR_ARROW); | ||||
| 				timo_cursor = 0; | ||||
| 				tns.sel = fileidx; | ||||
| 				changed = tns.dirty = 1; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* miscellaneous */ | ||||
| 			case XK_a: | ||||
| 				img_toggle_antialias(&img); | ||||
| 				changed = 1; | ||||
| 				break; | ||||
| 			case XK_A: | ||||
| 				img.alpha ^= 1; | ||||
| 				changed = 1; | ||||
| 				break; | ||||
| 			case XK_D: | ||||
| 				remove_file(fileidx, 1); | ||||
| 				changed = load_image(fileidx >= filecnt ? filecnt - 1 : fileidx); | ||||
| 				break; | ||||
| 			case XK_r: | ||||
| 				changed = load_image(fileidx); | ||||
| 				break; | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* thumbnail mode */ | ||||
| 		switch (ksym) { | ||||
| 			/* open selected image */ | ||||
| 			case XK_Return: | ||||
| 				load_image(tns.sel); | ||||
| 				mode = MODE_NORMAL; | ||||
| 				changed = 1; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* move selection */ | ||||
| 			case XK_h: | ||||
| 			case XK_Left: | ||||
| 				changed = tns_move_selection(&tns, &win, DIR_LEFT); | ||||
| 				break; | ||||
| 			case XK_j: | ||||
| 			case XK_Down: | ||||
| 				changed = tns_move_selection(&tns, &win, DIR_DOWN); | ||||
| 				break; | ||||
| 			case XK_k: | ||||
| 			case XK_Up: | ||||
| 				changed = tns_move_selection(&tns, &win, DIR_UP); | ||||
| 				break; | ||||
| 			case XK_l: | ||||
| 			case XK_Right: | ||||
| 				changed = tns_move_selection(&tns, &win, DIR_RIGHT); | ||||
| 				break; | ||||
| 			case XK_g: | ||||
| 				if (tns.sel != 0) { | ||||
| 					tns.sel = 0; | ||||
| 					changed = tns.dirty = 1; | ||||
| 				} | ||||
| 				break; | ||||
| 			case XK_G: | ||||
| 				if (tns.sel != tns.cnt - 1) { | ||||
| 					tns.sel = tns.cnt - 1; | ||||
| 					changed = tns.dirty = 1; | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			/* miscellaneous */ | ||||
| 			case XK_D: | ||||
| 				if (tns.sel < tns.cnt) { | ||||
| 					remove_file(tns.sel, 1); | ||||
| 					changed = tns.dirty = 1; | ||||
| 					if (tns.sel >= tns.cnt) | ||||
| 						tns.sel = tns.cnt - 1; | ||||
| 				} | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* common key mappings */ | ||||
| 	switch (ksym) { | ||||
| 		case XK_q: | ||||
| 			cleanup(); | ||||
| 			exit(0); | ||||
| 		case XK_f: | ||||
| 			win_toggle_fullscreen(&win); | ||||
| 			if (mode == MODE_NORMAL) | ||||
| 				img.checkpan = 1; | ||||
| 			else | ||||
| 				tns.dirty = 1; | ||||
| 			timo_redraw = TO_WIN_RESIZE; | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (changed) | ||||
| 		redraw(); | ||||
| } | ||||
| 
 | ||||
| void on_buttonpress(XButtonEvent *bev) { | ||||
| 	int changed, sel; | ||||
| 	unsigned int mask; | ||||
| 
 | ||||
| 	if (!bev) | ||||
| 		return; | ||||
| 
 | ||||
| 	mask = CLEANMASK(bev->state); | ||||
| 	changed = 0; | ||||
| 
 | ||||
| 	if (mode == MODE_NORMAL) { | ||||
| 		if (!drag) { | ||||
| 			win_set_cursor(&win, CURSOR_ARROW); | ||||
| 			timo_cursor = TO_CURSOR_HIDE; | ||||
| 		} | ||||
| 
 | ||||
| 		switch (bev->button) { | ||||
| 			case Button1: | ||||
| 				if (fileidx + 1 < filecnt) | ||||
| 					changed = load_image(fileidx + 1); | ||||
| 				break; | ||||
| 			case Button2: | ||||
| 				mox = bev->x; | ||||
| 				moy = bev->y; | ||||
| 				win_set_cursor(&win, CURSOR_HAND); | ||||
| 				timo_cursor = 0; | ||||
| 				drag = 1; | ||||
| 				break; | ||||
| 			case Button3: | ||||
| 				if (fileidx > 0) | ||||
| 					changed = load_image(fileidx - 1); | ||||
| 				break; | ||||
| 			case Button4: | ||||
| 				if (mask == ControlMask) | ||||
| 					changed = img_zoom_in(&img, &win); | ||||
| 				else if (mask == ShiftMask) | ||||
| 					changed = img_pan(&img, &win, DIR_LEFT, 0); | ||||
| 				else | ||||
| 					changed = img_pan(&img, &win, DIR_UP, 0); | ||||
| 				break; | ||||
| 			case Button5: | ||||
| 				if (mask == ControlMask) | ||||
| 					changed = img_zoom_out(&img, &win); | ||||
| 				else if (mask == ShiftMask) | ||||
| 					changed = img_pan(&img, &win, DIR_RIGHT, 0); | ||||
| 				else | ||||
| 					changed = img_pan(&img, &win, DIR_DOWN, 0); | ||||
| 				break; | ||||
| 			case 6: | ||||
| 				changed = img_pan(&img, &win, DIR_LEFT, 0); | ||||
| 				break; | ||||
| 			case 7: | ||||
| 				changed = img_pan(&img, &win, DIR_RIGHT, 0); | ||||
| 				break; | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* thumbnail mode */ | ||||
| 		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_NORMAL; | ||||
| 						timo_cursor = TO_CURSOR_HIDE; | ||||
| 					} else { | ||||
| 						tns_highlight(&tns, &win, tns.sel, False); | ||||
| 						tns_highlight(&tns, &win, sel, True); | ||||
| 						tns.sel = sel; | ||||
| 					} | ||||
| 					changed = 1; | ||||
| 					break; | ||||
| 				} | ||||
| 				break; | ||||
| 			case Button4: | ||||
| 				changed = tns_scroll(&tns, DIR_UP); | ||||
| 				break; | ||||
| 			case Button5: | ||||
| 				changed = tns_scroll(&tns, DIR_DOWN); | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (changed) | ||||
| 		redraw(); | ||||
| } | ||||
| 
 | ||||
| void on_motionnotify(XMotionEvent *mev) { | ||||
| 	if (!mev) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (mev->x >= 0 && mev->x <= win.w && mev->y >= 0 && mev->y <= win.h) { | ||||
| 		if (img_move(&img, &win, mev->x - mox, mev->y - moy)) | ||||
| 			timo_redraw = TO_IMAGE_DRAG; | ||||
| 
 | ||||
| 		mox = mev->x; | ||||
| 		moy = mev->y; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void run() { | ||||
| 	int xfd, timeout; | ||||
| 	fd_set fds; | ||||
| 	struct timeval tt, t0, t1; | ||||
| 	XEvent ev; | ||||
| 
 | ||||
| 	drag = 0; | ||||
| 	timo_cursor = mode == MODE_NORMAL ? TO_CURSOR_HIDE : 0; | ||||
| 
 | ||||
| 	redraw(); | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		if (mode == MODE_THUMBS && tns.cnt < filecnt) { | ||||
| 			win_set_cursor(&win, CURSOR_WATCH); | ||||
| 			gettimeofday(&t0, 0); | ||||
| 
 | ||||
| 			while (tns.cnt < filecnt && !XPending(win.env.dpy)) { | ||||
| 				if (tns_load(&tns, tns.cnt, filenames[tns.cnt], 0)) | ||||
| 					++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) { | ||||
| 			gettimeofday(&t0, 0); | ||||
| 			if (timo_cursor && timo_redraw) | ||||
| 				timeout = MIN(timo_cursor, timo_redraw); | ||||
| 			else if (timo_cursor) | ||||
| 				timeout = timo_cursor; | ||||
| 			else | ||||
| 				timeout = timo_redraw; | ||||
| 			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 (!XPending(win.env.dpy) && (timo_cursor || timo_redraw)) | ||||
| 				continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!XNextEvent(win.env.dpy, &ev)) { | ||||
| 			switch (ev.type) { | ||||
| 				case KeyPress: | ||||
| 					on_keypress(&ev.xkey); | ||||
| 					break; | ||||
| 				case ButtonPress: | ||||
| 					on_buttonpress(&ev.xbutton); | ||||
| 					break; | ||||
| 				case ButtonRelease: | ||||
| 					if (ev.xbutton.button == Button2) { | ||||
| 						drag = 0; | ||||
| 						if (mode == MODE_NORMAL) { | ||||
| 							win_set_cursor(&win, CURSOR_ARROW); | ||||
| 							timo_cursor = TO_CURSOR_HIDE; | ||||
| 						} | ||||
| 					} | ||||
| 					break; | ||||
| 				case MotionNotify: | ||||
| 					if (drag) { | ||||
| 						on_motionnotify(&ev.xmotion); | ||||
| 					} else if (mode == MODE_NORMAL) { | ||||
| 						if (!timo_cursor) | ||||
| 							win_set_cursor(&win, CURSOR_ARROW); | ||||
| 						timo_cursor = TO_CURSOR_HIDE; | ||||
| 					} | ||||
| 					break; | ||||
| 				case ConfigureNotify: | ||||
| 					if (win_configure(&win, &ev.xconfigure)) { | ||||
| 						timo_redraw = TO_WIN_RESIZE; | ||||
| 						if (mode == MODE_NORMAL) | ||||
| 							img.checkpan = 1; | ||||
| 						else | ||||
| 							tns.dirty = 1; | ||||
| 					} | ||||
| 					break; | ||||
| 				case ClientMessage: | ||||
| 					if ((Atom) ev.xclient.data.l[0] == wm_delete_win) | ||||
| 						return; | ||||
| 					break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -17,6 +17,7 @@ | ||||
|  */ | ||||
| 
 | ||||
| #define _XOPEN_SOURCE | ||||
| #define _IMAGE_CONFIG | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
							
								
								
									
										8
									
								
								sxiv.1
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								sxiv.1
									
									
									
									
									
								
							| @ -150,16 +150,16 @@ Pan to top image edge. | ||||
| .B L | ||||
| Pan to right image edge. | ||||
| .TP | ||||
| .BR Ctrl-h ", " Ctrl-Left | ||||
| .BR { | ||||
| Pan image one window width left. | ||||
| .TP | ||||
| .BR Ctrl-j ", " Ctrl-Down ", " PageDn | ||||
| .BR PageDn | ||||
| Pan image one window height down. | ||||
| .TP | ||||
| .BR Ctrl-k ", " Ctrl-Up ", " PageUp | ||||
| .BR PageUp | ||||
| Pan image one window height up. | ||||
| .TP | ||||
| .BR Ctrl-l ", " Ctrl-Right | ||||
| .BR } | ||||
| Pan image one window width right. | ||||
| .SS Rotation | ||||
| .TP | ||||
|  | ||||
							
								
								
									
										10
									
								
								thumbs.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								thumbs.c
									
									
									
									
									
								
							| @ -16,6 +16,8 @@ | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
|  */ | ||||
| 
 | ||||
| #define _THUMBS_CONFIG | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sys/time.h> | ||||
| @ -205,7 +207,7 @@ void tns_free(tns_t *tns) { | ||||
| 		return; | ||||
| 
 | ||||
| 	if (tns->thumbs) { | ||||
| 		for (i = 0; i < tns->cnt; ++i) { | ||||
| 		for (i = 0; i < tns->cnt; i++) { | ||||
| 			if (tns->thumbs[i].im) { | ||||
| 				imlib_context_set_image(tns->thumbs[i].im); | ||||
| 				imlib_free_image(); | ||||
| @ -337,7 +339,7 @@ void tns_render(tns_t *tns, win_t *win) { | ||||
| 	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; | ||||
| 
 | ||||
| 	for (i = 0; i < cnt; ++i) { | ||||
| 	for (i = 0; i < cnt; i++) { | ||||
| 		t = &tns->thumbs[tns->first + i]; | ||||
| 		t->x = x + (THUMB_SIZE - t->w) / 2; | ||||
| 		t->y = y + (THUMB_SIZE - t->h) / 2; | ||||
| @ -391,11 +393,11 @@ int tns_move_selection(tns_t *tns, win_t *win, direction_t dir) { | ||||
| 	switch (dir) { | ||||
| 		case DIR_LEFT: | ||||
| 			if (tns->sel > 0) | ||||
| 				--tns->sel; | ||||
| 				tns->sel--; | ||||
| 			break; | ||||
| 		case DIR_RIGHT: | ||||
| 			if (tns->sel < tns->cnt - 1) | ||||
| 				++tns->sel; | ||||
| 				tns->sel++; | ||||
| 			break; | ||||
| 		case DIR_UP: | ||||
| 			if (tns->sel >= tns->cols) | ||||
|  | ||||
							
								
								
									
										14
									
								
								types.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								types.h
									
									
									
									
									
								
							| @ -2,31 +2,25 @@ | ||||
| #define TYPES_H | ||||
| 
 | ||||
| typedef enum { | ||||
| 	MODE_NORMAL = 0, | ||||
| 	MODE_NORMAL, | ||||
| 	MODE_THUMBS | ||||
| } appmode_t; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	char key; | ||||
| 	int reload; | ||||
| 	const char *cmdline; | ||||
| } command_t; | ||||
| 
 | ||||
| typedef enum { | ||||
| 	DIR_LEFT = 0, | ||||
| 	DIR_LEFT, | ||||
| 	DIR_RIGHT, | ||||
| 	DIR_UP, | ||||
| 	DIR_DOWN | ||||
| } direction_t; | ||||
| 
 | ||||
| typedef enum { | ||||
| 	SCALE_DOWN = 0, | ||||
| 	SCALE_DOWN, | ||||
| 	SCALE_FIT, | ||||
| 	SCALE_ZOOM | ||||
| } scalemode_t; | ||||
| 
 | ||||
| typedef enum { | ||||
| 	CURSOR_ARROW = 0, | ||||
| 	CURSOR_ARROW, | ||||
| 	CURSOR_NONE, | ||||
| 	CURSOR_HAND, | ||||
| 	CURSOR_WATCH | ||||
|  | ||||
							
								
								
									
										8
									
								
								util.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								util.c
									
									
									
									
									
								
							| @ -26,8 +26,10 @@ | ||||
| #include "options.h" | ||||
| #include "util.h" | ||||
| 
 | ||||
| #define DNAME_CNT 512 | ||||
| #define FNAME_LEN 1024 | ||||
| enum { | ||||
| 	DNAME_CNT = 512, | ||||
| 	FNAME_LEN = 1024 | ||||
| }; | ||||
| 
 | ||||
| void cleanup(); | ||||
| 
 | ||||
| @ -78,7 +80,7 @@ void size_readable(float *size, const char **unit) { | ||||
| 	const char *units[] = { "", "K", "M", "G" }; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < LEN(units) && *size > 1024; ++i) | ||||
| 	for (i = 0; i < LEN(units) && *size > 1024; i++) | ||||
| 		*size /= 1024; | ||||
| 	*unit = units[MIN(i, LEN(units) - 1)]; | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Bert
						Bert