add stuff
This commit is contained in:
		
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -21,3 +21,10 @@
 | 
			
		||||
*.i*86
 | 
			
		||||
*.x86_64
 | 
			
		||||
*.hex
 | 
			
		||||
/sent
 | 
			
		||||
 | 
			
		||||
# vim
 | 
			
		||||
*.swp
 | 
			
		||||
*~
 | 
			
		||||
 | 
			
		||||
config.h
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
			
		||||
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
 | 
			
		||||
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
 | 
			
		||||
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
 | 
			
		||||
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