add stuff
This commit is contained in:
		
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -21,3 +21,10 @@ | |||||||
| *.i*86 | *.i*86 | ||||||
| *.x86_64 | *.x86_64 | ||||||
| *.hex | *.hex | ||||||
|  | /sent | ||||||
|  |  | ||||||
|  | # vim | ||||||
|  | *.swp | ||||||
|  | *~ | ||||||
|  |  | ||||||
|  | config.h | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| The MIT License (MIT) | The MIT License (MIT) | ||||||
|  |  | ||||||
| Copyright (c) 2014 schachmat | Copyright (c) 2014 markus.teich@stusta.mhn.de | ||||||
|  |  | ||||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
| of this software and associated documentation files (the "Software"), to deal | of this software and associated documentation files (the "Software"), to deal | ||||||
| @ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
| SOFTWARE. | SOFTWARE. | ||||||
|  | |||||||
							
								
								
									
										56
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | # sent - plain text presentation tool | ||||||
|  | # See LICENSE file for copyright and license details. | ||||||
|  |  | ||||||
|  | include config.mk | ||||||
|  |  | ||||||
|  | SRC = sent.c | ||||||
|  | OBJ = ${SRC:.c=.o} | ||||||
|  |  | ||||||
|  | all: options sent cscope | ||||||
|  |  | ||||||
|  | options: | ||||||
|  | 	@echo sent build options: | ||||||
|  | 	@echo "CFLAGS   = ${CFLAGS}" | ||||||
|  | 	@echo "LDFLAGS  = ${LDFLAGS}" | ||||||
|  | 	@echo "CC       = ${CC}" | ||||||
|  |  | ||||||
|  | config.h: | ||||||
|  | 	cp config.def.h config.h | ||||||
|  |  | ||||||
|  | .c.o: | ||||||
|  | 	@echo CC $< | ||||||
|  | 	@${CC} -c ${CFLAGS} $< | ||||||
|  |  | ||||||
|  | ${OBJ}: config.h config.mk | ||||||
|  |  | ||||||
|  | sent: ${OBJ} | ||||||
|  | 	@echo CC -o $@ | ||||||
|  | 	@${CC} -o $@ ${OBJ} ${LDFLAGS} | ||||||
|  |  | ||||||
|  | cscope: ${SRC} config.h | ||||||
|  | 	@echo cScope | ||||||
|  | 	@cscope -R -b | ||||||
|  |  | ||||||
|  | clean: | ||||||
|  | 	@echo cleaning | ||||||
|  | 	@rm -f sent ${OBJ} sent-${VERSION}.tar.gz | ||||||
|  |  | ||||||
|  | dist: clean | ||||||
|  | 	@echo creating dist tarball | ||||||
|  | 	@mkdir -p sent-${VERSION} | ||||||
|  | 	@cp -R LICENSE Makefile config.mk config.def.h ${SRC} sent-${VERSION} | ||||||
|  | 	@tar -cf sent-${VERSION}.tar sent-${VERSION} | ||||||
|  | 	@gzip sent-${VERSION}.tar | ||||||
|  | 	@rm -rf sent-${VERSION} | ||||||
|  |  | ||||||
|  | install: all | ||||||
|  | 	@echo installing executable file to ${DESTDIR}${PREFIX}/bin | ||||||
|  | 	@mkdir -p ${DESTDIR}${PREFIX}/bin | ||||||
|  | 	@cp -f sent ${DESTDIR}${PREFIX}/bin | ||||||
|  | 	@chmod 755 ${DESTDIR}${PREFIX}/bin/sent | ||||||
|  |  | ||||||
|  | uninstall: | ||||||
|  | 	@echo removing executable file from ${DESTDIR}${PREFIX}/bin | ||||||
|  | 	@rm -f ${DESTDIR}${PREFIX}/bin/sent | ||||||
|  |  | ||||||
|  | .PHONY: all options clean dist install uninstall cscope | ||||||
							
								
								
									
										63
									
								
								arg.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								arg.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | |||||||
|  | /* | ||||||
|  |  * Copy me if you can. | ||||||
|  |  * by 20h | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef ARG_H__ | ||||||
|  | #define ARG_H__ | ||||||
|  |  | ||||||
|  | extern char *argv0; | ||||||
|  |  | ||||||
|  | /* use main(int argc, char *argv[]) */ | ||||||
|  | #define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\ | ||||||
|  | 					argv[0] && argv[0][1]\ | ||||||
|  | 					&& argv[0][0] == '-';\ | ||||||
|  | 					argc--, argv++) {\ | ||||||
|  | 				char argc_;\ | ||||||
|  | 				char **argv_;\ | ||||||
|  | 				int brk_;\ | ||||||
|  | 				if (argv[0][1] == '-' && argv[0][2] == '\0') {\ | ||||||
|  | 					argv++;\ | ||||||
|  | 					argc--;\ | ||||||
|  | 					break;\ | ||||||
|  | 				}\ | ||||||
|  | 				for (brk_ = 0, argv[0]++, argv_ = argv;\ | ||||||
|  | 						argv[0][0] && !brk_;\ | ||||||
|  | 						argv[0]++) {\ | ||||||
|  | 					if (argv_ != argv)\ | ||||||
|  | 						break;\ | ||||||
|  | 					argc_ = argv[0][0];\ | ||||||
|  | 					switch (argc_) | ||||||
|  |  | ||||||
|  | /* Handles obsolete -NUM syntax */ | ||||||
|  | #define ARGNUM				case '0':\ | ||||||
|  | 					case '1':\ | ||||||
|  | 					case '2':\ | ||||||
|  | 					case '3':\ | ||||||
|  | 					case '4':\ | ||||||
|  | 					case '5':\ | ||||||
|  | 					case '6':\ | ||||||
|  | 					case '7':\ | ||||||
|  | 					case '8':\ | ||||||
|  | 					case '9' | ||||||
|  |  | ||||||
|  | #define ARGEND			}\ | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | #define ARGC()		argc_ | ||||||
|  |  | ||||||
|  | #define ARGNUMF(base)	(brk_ = 1, estrtol(argv[0], (base))) | ||||||
|  |  | ||||||
|  | #define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\ | ||||||
|  | 				((x), abort(), (char *)0) :\ | ||||||
|  | 				(brk_ = 1, (argv[0][1] != '\0')?\ | ||||||
|  | 					(&argv[0][1]) :\ | ||||||
|  | 					(argc--, argv++, argv[0]))) | ||||||
|  |  | ||||||
|  | #define ARGF()		((argv[0][1] == '\0' && argv[1] == NULL)?\ | ||||||
|  | 				(char *)0 :\ | ||||||
|  | 				(brk_ = 1, (argv[0][1] != '\0')?\ | ||||||
|  | 					(&argv[0][1]) :\ | ||||||
|  | 					(argc--, argv++, argv[0]))) | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										28
									
								
								config.def.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								config.def.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  |  | ||||||
|  | static char font[] = "-*-dejavu sans condensed-bold-r-*-*-0-0-*-*-*-0-*-*"; | ||||||
|  | #define NUMFONTS 30 | ||||||
|  | #define FONTSZ(x) ((int)(100.0 * powf(1.1288, (x)))) /* x in [0, NUMFONTS-1] */ | ||||||
|  |  | ||||||
|  | /* how much screen estate is to be used at max for the content */ | ||||||
|  | static float usablewidth = 0.75; | ||||||
|  | static float usableheight = 0.75; | ||||||
|  |  | ||||||
|  | static Mousekey mshortcuts[] = { | ||||||
|  | 	/* button         function        argument */ | ||||||
|  | 	{ Button1,        advance,        {.i = +1} }, | ||||||
|  | 	{ Button2,        advance,        {.i = -1} }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static Shortcut shortcuts[] = { | ||||||
|  | 	/* keysym         function        argument */ | ||||||
|  | 	{ XK_q,           quit,           {0} }, | ||||||
|  | 	{ XK_Right,       advance,        {.i = +1} }, | ||||||
|  | 	{ XK_Left,        advance,        {.i = -1} }, | ||||||
|  | 	{ XK_Return,      advance,        {.i = +1} }, | ||||||
|  | 	{ XK_BackSpace,   advance,        {.i = -1} }, | ||||||
|  | 	{ XK_Down,        advance,        {.i = +5} }, | ||||||
|  | 	{ XK_Up,          advance,        {.i = -5} }, | ||||||
|  | 	{ XK_Next,        advance,        {.i = +10} }, | ||||||
|  | 	{ XK_Prior,       advance,        {.i = -10} }, | ||||||
|  | }; | ||||||
							
								
								
									
										25
									
								
								config.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								config.mk
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | # sent version | ||||||
|  | VERSION = 0.1 | ||||||
|  |  | ||||||
|  | # Customize below to fit your system | ||||||
|  |  | ||||||
|  | # paths | ||||||
|  | PREFIX = /usr/local | ||||||
|  | MANPREFIX = ${PREFIX}/share/man | ||||||
|  |  | ||||||
|  | X11INC = /usr/X11R6/include | ||||||
|  | X11LIB = /usr/X11R6/lib | ||||||
|  |  | ||||||
|  | # includes and libs | ||||||
|  | INCS = -I. -I/usr/include -I${X11INC} | ||||||
|  | LIBS = -L/usr/lib -lc -lm -L${X11LIB} -lX11 | ||||||
|  |  | ||||||
|  | # flags | ||||||
|  | CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_XOPEN_SOURCE=600 | ||||||
|  | CFLAGS += -g -std=c99 -pedantic -Wall ${INCS} ${CPPFLAGS} | ||||||
|  | LDFLAGS += -g ${LIBS} | ||||||
|  | #CFLAGS += -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} | ||||||
|  | #LDFLAGS += ${LIBS} | ||||||
|  |  | ||||||
|  | # compiler and linker | ||||||
|  | CC ?= cc | ||||||
							
								
								
									
										468
									
								
								sent.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										468
									
								
								sent.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,468 @@ | |||||||
|  | /* See LICENSE for licence details. */ | ||||||
|  | #include <errno.h> | ||||||
|  | #include <math.h> | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <X11/keysym.h> | ||||||
|  | #include <X11/XKBlib.h> | ||||||
|  | #include <X11/Xatom.h> | ||||||
|  | #include <X11/Xlib.h> | ||||||
|  | #include <X11/Xutil.h> | ||||||
|  |  | ||||||
|  | #include "arg.h" | ||||||
|  |  | ||||||
|  | char *argv0; | ||||||
|  |  | ||||||
|  | /* macros */ | ||||||
|  | #define LEN(a)     (sizeof(a) / sizeof(a)[0]) | ||||||
|  | #define LIMIT(x, a, b)    (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  | 	char* text; | ||||||
|  | } Slide; | ||||||
|  |  | ||||||
|  | /* Purely graphic info */ | ||||||
|  | typedef struct { | ||||||
|  | 	Display *dpy; | ||||||
|  | 	Window win; | ||||||
|  | 	Atom wmdeletewin, netwmname; | ||||||
|  | 	Visual *vis; | ||||||
|  | 	XSetWindowAttributes attrs; | ||||||
|  | 	int scr; | ||||||
|  | 	int w, h; | ||||||
|  | } XWindow; | ||||||
|  |  | ||||||
|  | /* Drawing Context linked list*/ | ||||||
|  | struct DC{ | ||||||
|  | 	XFontStruct *font; | ||||||
|  | 	GC gc; | ||||||
|  | 	struct DC *next; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | typedef union { | ||||||
|  | 	int i; | ||||||
|  | 	unsigned int ui; | ||||||
|  | 	float f; | ||||||
|  | 	const void *v; | ||||||
|  | } Arg; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  | 	unsigned int b; | ||||||
|  | 	void (*func)(const Arg *); | ||||||
|  | 	const Arg arg; | ||||||
|  | } Mousekey; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  | 	KeySym keysym; | ||||||
|  | 	void (*func)(const Arg *); | ||||||
|  | 	const Arg arg; | ||||||
|  | } Shortcut; | ||||||
|  |  | ||||||
|  | /* function definitions used in config.h */ | ||||||
|  | static void advance(const Arg *); | ||||||
|  | static void quit(const Arg *); | ||||||
|  |  | ||||||
|  | /* config.h for applying patches and the configuration. */ | ||||||
|  | #include "config.h" | ||||||
|  |  | ||||||
|  | static Bool xfontisscalable(char *name); | ||||||
|  | static XFontStruct *xloadqueryscalablefont(char *name, int size); | ||||||
|  | static struct DC *getfontsize(char *str, size_t len, int *width, int *height); | ||||||
|  | static void cleanup(struct DC *cur); | ||||||
|  | static void eprintf(const char *, ...); | ||||||
|  | static void load(FILE *fp); | ||||||
|  | static void advance(const Arg *arg); | ||||||
|  | static void quit(const Arg *arg); | ||||||
|  | static void run(); | ||||||
|  | static void usage(); | ||||||
|  | static void xdraw(); | ||||||
|  | static void xhints(); | ||||||
|  | static void xinit(); | ||||||
|  | static void xloadfonts(char *); | ||||||
|  |  | ||||||
|  | static void bpress(XEvent *); | ||||||
|  | static void cmessage(XEvent *); | ||||||
|  | static void expose(XEvent *); | ||||||
|  | static void kpress(XEvent *); | ||||||
|  | static void resize(XEvent *); | ||||||
|  |  | ||||||
|  | /* Globals */ | ||||||
|  | static Slide *slides = NULL; | ||||||
|  | static int idx = 0; | ||||||
|  | static int slidecount = 0; | ||||||
|  | static XWindow xw; | ||||||
|  | static struct DC dc; | ||||||
|  | static int running = 1; | ||||||
|  | static char *opt_font = NULL; | ||||||
|  |  | ||||||
|  | static void (*handler[LASTEvent])(XEvent *) = { | ||||||
|  | 	[ButtonPress] = bpress, | ||||||
|  | 	[ClientMessage] = cmessage, | ||||||
|  | 	[ConfigureNotify] = resize, | ||||||
|  | 	[Expose] = expose, | ||||||
|  | 	[KeyPress] = kpress, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Bool xfontisscalable(char *name) | ||||||
|  | { | ||||||
|  | 	int i, field; | ||||||
|  |  | ||||||
|  | 	if (!name || name[0] != '-') | ||||||
|  | 		return False; | ||||||
|  |  | ||||||
|  | 	for (i = field = 0; name[i] != '\0'; i++) { | ||||||
|  | 		if (name[i] == '-') { | ||||||
|  | 			field++; | ||||||
|  | 			if ((field == 7) || (field == 8) || (field == 12)) | ||||||
|  | 				if ((name[i+1] != '0') || (name[i+2] != '-')) | ||||||
|  | 					return False; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return field == 14; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | XFontStruct *xloadqueryscalablefont(char *name, int size) | ||||||
|  | { | ||||||
|  | 	int i, j, field; | ||||||
|  | 	char newname[500]; | ||||||
|  | 	int resx, resy; | ||||||
|  |  | ||||||
|  | 	if (!name || name[0] != '-') | ||||||
|  | 		return NULL; | ||||||
|  | 	/* calculate our screen resolution in dots per inch. 25.4mm = 1 inch */ | ||||||
|  | 	resx = DisplayWidth(xw.dpy, xw.scr)/(DisplayWidthMM(xw.dpy, xw.scr)/25.4); | ||||||
|  | 	resy = DisplayHeight(xw.dpy, xw.scr)/(DisplayHeightMM(xw.dpy, xw.scr)/25.4); | ||||||
|  | 	/* copy the font name, changing the scalable fields as we do so */ | ||||||
|  | 	for (i = j = field = 0; name[i] != '\0' && field <= 14; i++) { | ||||||
|  | 		newname[j++] = name[i]; | ||||||
|  | 		if (name[i] == '-') { | ||||||
|  | 			field++; | ||||||
|  | 			switch (field) { | ||||||
|  | 				case 7:  /* pixel size */ | ||||||
|  | 				case 12: /* average width */ | ||||||
|  | 					/* change from "-0-" to "-*-" */ | ||||||
|  | 					newname[j] = '*'; | ||||||
|  | 					j++; | ||||||
|  | 					if (name[i+1] != '\0') i++; | ||||||
|  | 					break; | ||||||
|  | 				case 8:  /* point size */ | ||||||
|  | 					/* change from "-0-" to "-<size>-" */ | ||||||
|  | 					sprintf(&newname[j], "%d", size); | ||||||
|  | 					while (newname[j] != '\0') j++; | ||||||
|  | 					if (name[i+1] != '\0') i++; | ||||||
|  | 					break; | ||||||
|  | 				case 9:  /* x-resolution */ | ||||||
|  | 				case 10: /* y-resolution */ | ||||||
|  | 					/* change from an unspecified resolution to resx or resy */ | ||||||
|  | 					sprintf(&newname[j], "%d", (field == 9) ? resx : resy); | ||||||
|  | 					while (newname[j] != '\0') j++; | ||||||
|  | 					while ((name[i+1] != '-') && (name[i+1] != '\0')) i++; | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	newname[j] = '\0'; | ||||||
|  | 	return (field != 14) ? NULL : XLoadQueryFont(xw.dpy, newname); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct DC *getfontsize(char *str, size_t len, int *width, int *height) | ||||||
|  | { | ||||||
|  | 	XCharStruct info; | ||||||
|  | 	int unused; | ||||||
|  | 	struct DC *pre = &dc; | ||||||
|  | 	struct DC *cur = &dc; | ||||||
|  |  | ||||||
|  | 	do { | ||||||
|  | 		XTextExtents(cur->font, str, len, &unused, &unused, &unused, &info); | ||||||
|  | 		if (info.width > usablewidth * xw.w | ||||||
|  | 				|| info.ascent + info.descent > usableheight * xw.h) | ||||||
|  | 			break; | ||||||
|  | 		pre = cur; | ||||||
|  | 	} while ((cur = cur->next)); | ||||||
|  |  | ||||||
|  | 	XTextExtents(pre->font, "o", 1, &unused, &unused, &unused, &info); | ||||||
|  | 	*height = info.ascent; | ||||||
|  | 	*width = XTextWidth(pre->font, str, len); | ||||||
|  | 	return pre; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cleanup(struct DC *cur) | ||||||
|  | { | ||||||
|  | 	XFreeFont(xw.dpy, cur->font); | ||||||
|  | 	XFreeGC(xw.dpy, cur->gc); | ||||||
|  |  | ||||||
|  | 	if (cur->next) { | ||||||
|  | 		cleanup(cur->next); | ||||||
|  | 		cur->next = NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (cur != &dc) { | ||||||
|  | 		free(cur); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	XDestroyWindow(xw.dpy, xw.win); | ||||||
|  | 	XSync(xw.dpy, False); | ||||||
|  | 	XCloseDisplay(xw.dpy); | ||||||
|  | 	if (slides) { | ||||||
|  | 		free(slides); | ||||||
|  | 		slides = NULL; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void eprintf(const char *fmt, ...) | ||||||
|  | { | ||||||
|  | 	va_list ap; | ||||||
|  |  | ||||||
|  | 	va_start(ap, fmt); | ||||||
|  | 	vfprintf(stderr, fmt, ap); | ||||||
|  | 	va_end(ap); | ||||||
|  |  | ||||||
|  | 	if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') { | ||||||
|  | 		fputc(' ', stderr); | ||||||
|  | 		perror(NULL); | ||||||
|  | 	} else { | ||||||
|  | 		fputc('\n', stderr); | ||||||
|  | 	} | ||||||
|  | 	exit(EXIT_FAILURE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void load(FILE *fp) | ||||||
|  | { | ||||||
|  | 	static size_t size = 0; | ||||||
|  | 	char buf[BUFSIZ], *p; | ||||||
|  | 	size_t i; | ||||||
|  |  | ||||||
|  | 	/* read each line from stdin and add it to the item list */ | ||||||
|  | 	for (i = slidecount; fgets(buf, sizeof(buf), fp); i++) { | ||||||
|  | 		if ((i+1) * sizeof(*slides) >= size) | ||||||
|  | 			if (!(slides = realloc(slides, (size += BUFSIZ)))) | ||||||
|  | 				eprintf("cannot realloc %u bytes:", size); | ||||||
|  | 		if ((p = strchr(buf, '\n'))) | ||||||
|  | 			*p = '\0'; | ||||||
|  | 		if (!(slides[i].text = strdup(buf))) | ||||||
|  | 			eprintf("cannot strdup %u bytes:", strlen(buf)+1); | ||||||
|  | 	} | ||||||
|  | 	if (slides) | ||||||
|  | 		slides[i].text = NULL; | ||||||
|  | 	slidecount = i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void advance(const Arg *arg) | ||||||
|  | { | ||||||
|  | 	int new_idx = idx + arg->i; | ||||||
|  | 	LIMIT(new_idx, 0, slidecount-1); | ||||||
|  | 	if (new_idx != idx) { | ||||||
|  | 		idx = new_idx; | ||||||
|  | 		xdraw(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void quit(const Arg *arg) | ||||||
|  | { | ||||||
|  | 	running = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void run() | ||||||
|  | { | ||||||
|  | 	XEvent ev; | ||||||
|  |  | ||||||
|  | 	/* Waiting for window mapping */ | ||||||
|  | 	while (1) { | ||||||
|  | 		XNextEvent(xw.dpy, &ev); | ||||||
|  | 		if (ev.type == ConfigureNotify) { | ||||||
|  | 			xw.w = ev.xconfigure.width; | ||||||
|  | 			xw.h = ev.xconfigure.height; | ||||||
|  | 		} else if (ev.type == MapNotify) { | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	while (running) { | ||||||
|  | 		XNextEvent(xw.dpy, &ev); | ||||||
|  | 		if (handler[ev.type]) | ||||||
|  | 			(handler[ev.type])(&ev); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void usage() | ||||||
|  | { | ||||||
|  | 	eprintf("sent " VERSION " (c) 2014 markus.teich@stusta.mhn.de\n" \ | ||||||
|  | 	"usage: sent [-f font] FILE1 [FILE2 ...]", argv0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void xdraw() | ||||||
|  | { | ||||||
|  | 	int line_len = strlen(slides[idx].text); | ||||||
|  | 	int height; | ||||||
|  | 	int width; | ||||||
|  | 	struct DC *dc = getfontsize(slides[idx].text, line_len, &width, &height); | ||||||
|  |  | ||||||
|  | 	XClearWindow(xw.dpy, xw.win); | ||||||
|  | 	XDrawString(xw.dpy, xw.win, dc->gc, (xw.w - width)/2, (xw.h + height)/2, | ||||||
|  | 			slides[idx].text, line_len); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void xhints() | ||||||
|  | { | ||||||
|  | 	XClassHint class = {.res_name = "sent", .res_class = "presenter"}; | ||||||
|  | 	XWMHints wm = {.flags = InputHint, .input = True}; | ||||||
|  | 	XSizeHints *sizeh = NULL; | ||||||
|  |  | ||||||
|  | 	if (!(sizeh = XAllocSizeHints())) | ||||||
|  | 		eprintf("sent: Could not alloc size hints"); | ||||||
|  |  | ||||||
|  | 	sizeh->flags = PSize; | ||||||
|  | 	sizeh->height = xw.h; | ||||||
|  | 	sizeh->width = xw.w; | ||||||
|  |  | ||||||
|  | 	XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, &class); | ||||||
|  | 	XFree(sizeh); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void xinit() | ||||||
|  | { | ||||||
|  | 	XTextProperty prop; | ||||||
|  |  | ||||||
|  | 	if (!(xw.dpy = XOpenDisplay(NULL))) | ||||||
|  | 		eprintf("Can't open display."); | ||||||
|  | 	xw.scr = XDefaultScreen(xw.dpy); | ||||||
|  | 	xw.vis = XDefaultVisual(xw.dpy, xw.scr); | ||||||
|  | 	xw.w = DisplayWidth(xw.dpy, xw.scr); | ||||||
|  | 	xw.h = DisplayHeight(xw.dpy, xw.scr); | ||||||
|  |  | ||||||
|  | 	xw.attrs.background_pixel = WhitePixel(xw.dpy, xw.scr); | ||||||
|  | 	xw.attrs.bit_gravity = CenterGravity; | ||||||
|  | 	xw.attrs.event_mask = KeyPressMask | ExposureMask | StructureNotifyMask | ||||||
|  | 		| ButtonMotionMask | ButtonPressMask; | ||||||
|  |  | ||||||
|  | 	xw.win = XCreateWindow(xw.dpy, XRootWindow(xw.dpy, xw.scr), 0, 0, | ||||||
|  | 			xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, xw.vis, | ||||||
|  | 			CWBackPixel | CWBitGravity | CWEventMask, &xw.attrs); | ||||||
|  |  | ||||||
|  | 	xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); | ||||||
|  | 	xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); | ||||||
|  | 	XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); | ||||||
|  |  | ||||||
|  | 	xloadfonts(opt_font ? opt_font : font); | ||||||
|  |  | ||||||
|  | 	XStringListToTextProperty(&argv0, 1, &prop); | ||||||
|  | 	XSetWMName(xw.dpy, xw.win, &prop); | ||||||
|  | 	XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); | ||||||
|  | 	XFree(prop.value); | ||||||
|  | 	XMapWindow(xw.dpy, xw.win); | ||||||
|  | 	xhints(); | ||||||
|  | 	XSync(xw.dpy, False); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void xloadfonts(char *fontstr) | ||||||
|  | { | ||||||
|  | 	int count = 0; | ||||||
|  | 	int i = 0; | ||||||
|  | 	XFontStruct *fnt; | ||||||
|  | 	XGCValues gcvalues; | ||||||
|  | 	struct DC *cur = &dc; | ||||||
|  | 	char **fstr = XListFonts(xw.dpy, fontstr, 42, &count); | ||||||
|  |  | ||||||
|  | 	while (count-- && !xfontisscalable(fstr[count])) | ||||||
|  | 		; /* nothing, just get first scalable font result */ | ||||||
|  |  | ||||||
|  | 	if (count < 0) | ||||||
|  | 		eprintf("sent: could not find a scalable font matching %s", fontstr); | ||||||
|  |  | ||||||
|  | 	memset(&gcvalues, 0, sizeof(gcvalues)); | ||||||
|  |  | ||||||
|  | 	do { | ||||||
|  | 		if (!(fnt = xloadqueryscalablefont(fstr[count], FONTSZ(i)))) { | ||||||
|  | 			i++; | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		cur->gc = XCreateGC(xw.dpy, XRootWindow(xw.dpy, xw.scr), 0, &gcvalues); | ||||||
|  | 		cur->font = fnt; | ||||||
|  | 		XSetFont(xw.dpy, cur->gc, fnt->fid); | ||||||
|  | 		XSetForeground(xw.dpy, cur->gc, BlackPixel(xw.dpy, xw.scr)); | ||||||
|  | 		cur->next = (++i < NUMFONTS) ? malloc(sizeof(struct DC)) : NULL; | ||||||
|  | 		cur = cur->next; | ||||||
|  | 	} while (cur && i < NUMFONTS); | ||||||
|  |  | ||||||
|  | 	if (cur == &dc) | ||||||
|  | 		eprintf("sent: could not load fonts."); | ||||||
|  |  | ||||||
|  | 	XFreeFontNames(fstr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void bpress(XEvent *e) | ||||||
|  | { | ||||||
|  | 	unsigned int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < LEN(mshortcuts); i++) | ||||||
|  | 		if (e->xbutton.button == mshortcuts[i].b && mshortcuts[i].func) | ||||||
|  | 			mshortcuts[i].func(&(mshortcuts[i].arg)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmessage(XEvent *e) | ||||||
|  | { | ||||||
|  | 	if (e->xclient.data.l[0] == xw.wmdeletewin) | ||||||
|  | 		running = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void expose(XEvent *e) | ||||||
|  | { | ||||||
|  | 	if (0 == e->xexpose.count) | ||||||
|  | 		xdraw(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void kpress(XEvent *e) | ||||||
|  | { | ||||||
|  | 	unsigned int i; | ||||||
|  | 	KeySym sym; | ||||||
|  |  | ||||||
|  | 	sym = XkbKeycodeToKeysym(xw.dpy, (KeyCode)e->xkey.keycode, 0, 0); | ||||||
|  | 	for (i = 0; i < LEN(shortcuts); i++) | ||||||
|  | 		if (sym == shortcuts[i].keysym && shortcuts[i].func) | ||||||
|  | 			shortcuts[i].func(&(shortcuts[i].arg)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void resize(XEvent *e) | ||||||
|  | { | ||||||
|  | 	xw.w = e->xconfigure.width; | ||||||
|  | 	xw.h = e->xconfigure.height; | ||||||
|  | 	xdraw(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	FILE *fp = NULL; | ||||||
|  |  | ||||||
|  | 	ARGBEGIN { | ||||||
|  | 	case 'f': | ||||||
|  | 		opt_font = EARGF(usage()); | ||||||
|  | 		break; | ||||||
|  | 	case 'v': | ||||||
|  | 	default: | ||||||
|  | 		usage(); | ||||||
|  | 	} ARGEND; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < argc; i++) { | ||||||
|  | 		if ((fp = strcmp(argv[i], "-") ? fopen(argv[i], "r") : stdin)) { | ||||||
|  | 			load(fp); | ||||||
|  | 			fclose(fp); | ||||||
|  | 		} else { | ||||||
|  | 			eprintf("could not open file %s for reading:", argv[i]); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (!slides || !slides[0].text) | ||||||
|  | 		usage(); | ||||||
|  |  | ||||||
|  | 	xinit(); | ||||||
|  | 	run(); | ||||||
|  |  | ||||||
|  | 	cleanup(&dc); | ||||||
|  | 	return EXIT_SUCCESS; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user