changeset 0:e7f1035f10d4

lcdemu: initial import from freecalypso-tools
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 14 Mar 2018 18:16:45 +0000
parents
children 8bdf7eef8b11
files lcdemu/Makefile lcdemu/globals.c lcdemu/globals.h lcdemu/main.c lcdemu/process.c lcdemu/window.c lcdemu/ximage.c lcdemu/xrm.c
diffstat 8 files changed, 640 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcdemu/Makefile	Wed Mar 14 18:16:45 2018 +0000
@@ -0,0 +1,17 @@
+CC=	gcc
+CFLAGS=	-O2
+PROG=	fc-lcdemu
+OBJS=	globals.o main.o process.o window.o ximage.o xrm.o
+INSTBIN=/usr/local/bin
+
+all:	${PROG}
+
+${PROG}: ${OBJS}
+	${CC} ${CFLAGS} -o $@ ${OBJS} -lX11
+
+install:	${PROG}
+	mkdir -p ${INSTBIN}
+	install -c ${PROG} ${INSTBIN}
+
+clean:
+	rm -f *.o *.out *errs ${PROG}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcdemu/globals.c	Wed Mar 14 18:16:45 2018 +0000
@@ -0,0 +1,20 @@
+/*
+ * LCDemu based on HECterm by the same author
+ * Definitions of global variables
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/Xutil.h>
+
+char *progbasename, *proginstancename;
+char *mydisplayname;
+Display *mydisplay;
+Window mainwindow;
+GC mainwingc;
+int display_depth;
+
+XrmDatabase xrmdb_defaults, xrmdb_displayres, xrmdb_cmdline;
+XrmQuark xrmquark_topclass, xrmquark_topinstance;
+
+XImage *(*convert_function)();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcdemu/globals.h	Wed Mar 14 18:16:45 2018 +0000
@@ -0,0 +1,16 @@
+/*
+ * LCDemu based on HECterm by the same author
+ * External declaratiions for global variables
+ */
+
+extern char *progbasename, *proginstancename;
+extern char *mydisplayname;
+extern Display *mydisplay;
+extern Window mainwindow;
+extern GC mainwingc;
+extern int display_depth;
+
+extern XrmDatabase xrmdb_defaults, xrmdb_displayres, xrmdb_cmdline;
+extern XrmQuark xrmquark_topclass, xrmquark_topinstance;
+
+extern XImage *(*convert_function)();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcdemu/main.c	Wed Mar 14 18:16:45 2018 +0000
@@ -0,0 +1,166 @@
+/*
+ * LCDemu main module
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/Xutil.h>
+#include "globals.h"
+
+main(argc, argv)
+	char **argv;
+{
+	XrmInitialize();
+	process_cmdline(argc, argv);
+	open_display();
+	init_image_conversion();
+	load_resources();
+	create_our_window();
+	set_initial_window_title();
+	set_initial_icon_name();
+	create_mainwin_gc();
+	XMapWindow(mydisplay, mainwindow);
+	XFlush(mydisplay);
+
+	mainloop();
+	/* NOTREACHED */
+}
+
+process_cmdline(argc, argv)
+	char **argv;
+{
+	register char **ap, *opt;
+	char *rhost, *ruser;
+	int len;
+
+	if (argc < 1) {
+		fprintf(stderr, "fc-lcdemu: invalid invokation\n");
+		exit(1);
+	}
+	opt = rindex(argv[0], '/');
+	if (opt)
+		progbasename = opt + 1;
+	else
+		progbasename = argv[0];
+	proginstancename = progbasename;
+	for (ap = argv+1; *ap; ) {
+		if (**ap == '-')
+			opt = *ap++;
+		else
+			break;
+		if (!strcmp(opt, "-display")) {
+			if (!*ap) {
+argreq:				fprintf(stderr, "%s: %s requires an argument\n",
+					progbasename, opt);
+				exit(1);
+			}
+			mydisplayname = *ap++;
+			continue;
+		}
+		if (!strcmp(opt, "-name")) {
+			if (!*ap)
+				goto argreq;
+			proginstancename = *ap++;
+			continue;
+		}
+		if (!strcmp(opt, "-geometry") || !strcmp(opt, "-geom")) {
+			if (!*ap)
+				goto argreq;
+			XrmPutStringResource(&xrmdb_cmdline, "LCDemu.geometry",
+						*ap++);
+			continue;
+		}
+		if (!strcmp(opt, "-iconic")) {
+			XrmPutStringResource(&xrmdb_cmdline, "LCDemu.iconic",
+						"on");
+			continue;
+		}
+		if (!strcmp(opt, "-title")) {
+			if (!*ap)
+				goto argreq;
+			XrmPutStringResource(&xrmdb_cmdline, "LCDemu.title",
+						*ap++);
+			continue;
+		}
+		if (!strcmp(opt, "-borderwidth") || !strcmp(opt, "-bw")) {
+			if (!*ap)
+				goto argreq;
+			XrmPutStringResource(&xrmdb_cmdline, "*borderWidth",
+						*ap++);
+			continue;
+		}
+		if (!strcmp(opt, "-bordercolor") || !strcmp(opt, "-bd")) {
+			if (!*ap)
+				goto argreq;
+			XrmPutStringResource(&xrmdb_cmdline, "*borderColor",
+						*ap++);
+			continue;
+		}
+		if (!strcmp(opt, "-xrm")) {
+			if (!*ap)
+				goto argreq;
+			XrmPutLineResource(&xrmdb_cmdline, *ap++);
+			continue;
+		}
+		fprintf(stderr, "%s: %s: unrecognized option\n", progbasename,
+			opt);
+		exit(1);
+	}
+}
+
+open_display()
+{
+	if (!mydisplayname)
+		mydisplayname = getenv("DISPLAY");
+	if (!mydisplayname) {
+		fprintf(stderr, "%s: no X display available\n", progbasename);
+		exit(1);
+	}
+	mydisplay = XOpenDisplay(mydisplayname);
+	if (!mydisplay) {
+		fprintf(stderr, "%s: unable to open display %s\n", progbasename,
+			mydisplayname);
+		exit(1);
+	}
+}
+
+mainloop()
+{
+	register int i, cc;
+	XEvent event;
+	fd_set readfds;
+	int maxfd;
+	char buf[1024];
+
+	maxfd = ConnectionNumber(mydisplay) + 1;
+	for (;;) {
+		cc = XPending(mydisplay);
+		for (i = 0; i < cc; i++)
+			XNextEvent(mydisplay, &event);
+		XFlush(mydisplay);
+		FD_ZERO(&readfds);
+		FD_SET(0, &readfds);
+		FD_SET(ConnectionNumber(mydisplay), &readfds);
+		i = select(maxfd, &readfds, NULL, NULL, NULL);
+		if (i < 0) {
+			if (errno == EINTR)
+				continue;
+			perror("select");
+			exit(1);
+		}
+		if (FD_ISSET(0, &readfds)) {
+			cc = read(0, buf, sizeof buf);
+			if (cc > 0)
+				input_on_stdin(buf, cc);
+			else
+				exit(0);
+			XFlush(mydisplay);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcdemu/process.c	Wed Mar 14 18:16:45 2018 +0000
@@ -0,0 +1,108 @@
+/*
+ * Processing of LCD output (input to us)
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/Xutil.h>
+#include "globals.h"
+
+#define	MAX_WIDTH	176
+
+static unsigned
+hexdecode(str)
+	char *str;
+{
+	unsigned accum = 0;
+	int i, c, n;
+
+	for (i = 0; i < 4; i++) {
+		c = str[i];
+		if (isdigit(c))
+			n = c - '0';
+		else if (isupper(c))
+			n = c - 'A' + 10;
+		else
+			n = c - 'a' + 10;
+		accum <<= 4;
+		accum |= n;
+	}
+	return(accum);
+}
+
+process_input_line(line)
+	char *line;
+{
+	int blitrow, blitcol, npix;
+	uint16_t pix16[MAX_WIDTH];
+	char *cp;
+	XImage *xi;
+
+	for (cp = line; isspace(*cp); cp++)
+		;
+	if (!isdigit(*cp)) {
+inv:		fprintf(stderr, "fc-lcdemu: invalid input line\n");
+		exit(1);
+	}
+	blitrow = atoi(cp);
+	while (isdigit(*cp))
+		cp++;
+	if (!isspace(*cp))
+		goto inv;
+	while (isspace(*cp))
+		cp++;
+	if (!isdigit(*cp))
+		goto inv;
+	blitcol = atoi(cp);
+	while (isdigit(*cp))
+		cp++;
+	if (!isspace(*cp))
+		goto inv;
+	while (isspace(*cp))
+		cp++;
+	if (!isxdigit(*cp))
+		goto inv;
+	for (npix = 0; *cp; ) {
+		if (!isxdigit(cp[0]) || !isxdigit(cp[1]) ||
+		    !isxdigit(cp[2]) || !isxdigit(cp[3]))
+			goto inv;
+		if (npix >= MAX_WIDTH) {
+			fprintf(stderr,
+		"fc-lcdemu error: input line exceeds MAX_WIDTH of %d pixels\n",
+				MAX_WIDTH);
+			exit(1);
+		}
+		pix16[npix++] = hexdecode(cp);
+		cp += 4;
+	}
+	xi = convert_function(pix16, npix);
+	XPutImage(mydisplay, mainwindow, mainwingc, xi, 0, 0, blitcol, blitrow,
+		  npix, 1);
+	XDestroyImage(xi);
+}
+
+input_on_stdin(inbuf, incount)
+	char *inbuf;
+{
+	char *input_end = inbuf + incount;
+	static char linebuf[1024];
+	static int linesz;
+	char *cp;
+
+	for (cp = inbuf; cp < input_end; cp++) {
+		if (*cp == '\n') {
+			linebuf[linesz] = '\0';
+			process_input_line(linebuf);
+			linesz = 0;
+			continue;
+		}
+		if (linesz < sizeof(linebuf) - 1)
+			linebuf[linesz++] = *cp;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcdemu/window.c	Wed Mar 14 18:16:45 2018 +0000
@@ -0,0 +1,157 @@
+/*
+ * LCDemu based on HECterm by the same author
+ * X11 window creation functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/Xutil.h>
+#include "globals.h"
+
+extern char *xrm_lookup();
+
+create_our_window()
+{
+	XrmQuark instquarks[3], classquarks[3];
+	register char *cp;
+	register int i, geomask;
+	int pixwidth, pixheight, xpos, ypos;
+	XSetWindowAttributes xswa;
+	u_long xswamask;
+	XColor bdcolor;
+	XClassHint xclasshint;
+	XWMHints wmhints;
+	XSizeHints wm_normal_hints;
+
+	/* Determine our geometry */
+	instquarks[0] = xrmquark_topinstance;
+	classquarks[0] = xrmquark_topclass;
+	classquarks[1] = instquarks[1] = XrmStringToQuark("geometry");
+	instquarks[2] = classquarks[2] = NULLQUARK;
+	cp = xrm_lookup(instquarks, classquarks);
+	if (cp) {
+		geomask = XParseGeometry(cp, &xpos, &ypos, &pixwidth,
+					&pixheight);
+		free(cp);
+	} else
+		geomask = 0;
+	if (!(geomask & WidthValue))
+		pixwidth = 176;
+	if (!(geomask & HeightValue))
+		pixheight = 220;
+	if (!(geomask & XValue))
+		xpos = 0;
+	else if (geomask & XNegative)
+		xpos += DisplayWidth(mydisplay, DefaultScreen(mydisplay)) -
+			pixwidth;
+	if (!(geomask & YValue))
+		ypos = 0;
+	else if (geomask & YNegative)
+		ypos += DisplayHeight(mydisplay, DefaultScreen(mydisplay)) -
+			pixheight;
+	/* fill out XSetWindowAttributes */
+	xswa.event_mask = 0;	/* not interested in any events */
+	xswamask = CWEventMask;
+	/* border color */
+	classquarks[1] = instquarks[1] = XrmStringToQuark("borderColor");
+	cp = xrm_lookup(instquarks, classquarks);
+	if (cp) {
+		i = XParseColor(mydisplay, DefaultColormap(mydisplay,
+			DefaultScreen(mydisplay)), cp, &bdcolor);
+		free(cp);
+		if (i) {
+			i = XAllocColor(mydisplay, DefaultColormap(mydisplay,
+				DefaultScreen(mydisplay)), &bdcolor);
+			if (i) {
+				xswa.border_pixel = bdcolor.pixel;
+				xswamask |= CWBorderPixel;
+			}
+		}
+	}
+	/* border width */
+	classquarks[1] = instquarks[1] = XrmStringToQuark("borderWidth");
+	cp = xrm_lookup(instquarks, classquarks);
+	if (cp) {
+		i = atoi(cp);
+		free(cp);
+	} else
+		i = 2;
+	/* go for it! */
+	mainwindow = XCreateWindow(mydisplay, DefaultRootWindow(mydisplay),
+			xpos, ypos, pixwidth, pixheight, i, CopyFromParent,
+			InputOutput, CopyFromParent, xswamask, &xswa);
+	/* set window manager properties */
+	xclasshint.res_name = proginstancename;
+	xclasshint.res_class = "LEDemu";
+	XSetClassHint(mydisplay, mainwindow, &xclasshint);
+	wmhints.flags = InputHint | StateHint;
+	wmhints.input = False;
+	classquarks[1] = instquarks[1] = XrmStringToQuark("iconic");
+	cp = xrm_lookup(instquarks, classquarks);
+	if (cp) {
+		i = parse_boolean_resource(cp);
+		free(cp);
+	} else
+		i = 0;
+	wmhints.initial_state = i ? IconicState : NormalState;
+	XSetWMHints(mydisplay, mainwindow, &wmhints);
+	if (geomask & (WidthValue|HeightValue))
+		wm_normal_hints.flags = USSize;
+	else
+		wm_normal_hints.flags = PSize;
+	if (geomask & (XValue|YValue))
+		wm_normal_hints.flags |= USPosition;
+	XSetWMNormalHints(mydisplay, mainwindow, &wm_normal_hints);
+}
+
+set_initial_window_title()
+{
+	XrmQuark instquarks[3], classquarks[3];
+	register char *cp;
+	char buf[256];
+
+	instquarks[0] = xrmquark_topinstance;
+	classquarks[0] = xrmquark_topclass;
+	instquarks[1] = XrmStringToQuark("title");
+	classquarks[1] = XrmStringToQuark("Title");
+	instquarks[2] = classquarks[2] = NULLQUARK;
+	cp = xrm_lookup(instquarks, classquarks);
+	if (cp) {
+		XStoreName(mydisplay, mainwindow, cp);
+		free(cp);
+		return;
+	}
+	XStoreName(mydisplay, mainwindow, "Emulated LCD");
+}
+
+set_initial_icon_name()
+{
+	XrmQuark instquarks[3], classquarks[3];
+	register char *cp;
+
+	instquarks[0] = xrmquark_topinstance;
+	classquarks[0] = xrmquark_topclass;
+	instquarks[1] = XrmStringToQuark("iconName");
+	classquarks[1] = XrmStringToQuark("IconName");
+	instquarks[2] = classquarks[2] = NULLQUARK;
+	cp = xrm_lookup(instquarks, classquarks);
+	if (cp) {
+		XSetIconName(mydisplay, mainwindow, cp);
+		free(cp);
+		return;
+	}
+	XSetIconName(mydisplay, mainwindow, proginstancename);
+}
+
+create_mainwin_gc()
+{
+	XGCValues xgcval;
+
+	xgcval.graphics_exposures = False;
+	mainwingc = XCreateGC(mydisplay, mainwindow, GCGraphicsExposures,
+				&xgcval);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcdemu/ximage.c	Wed Mar 14 18:16:45 2018 +0000
@@ -0,0 +1,59 @@
+/*
+ * LCDemu based on HECterm by the same author
+ * XImage conversion muck
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/Xutil.h>
+#include "globals.h"
+
+XImage *
+convert_image_depth24(input, npix)
+	uint16_t *input;
+	int npix;
+{
+	uint32_t *imgbuf;
+	int i, in, r, g, b;
+	XImage *img;
+
+	imgbuf = malloc(npix * 4);
+	if (!imgbuf) {
+		perror("malloc");
+		exit(1);
+	}
+	for (i = 0; i < npix; i++) {
+		in = input[i];
+		r = (in & 0xF800) << 8;
+		g = (in & 0x07E0) << 5;
+		b = (in & 0x001F) << 3;
+		imgbuf[i] = r | g | b;
+	}
+	img = XCreateImage(mydisplay, CopyFromParent, display_depth, ZPixmap,
+			   0, (char *) imgbuf, npix, 1, 32, 0);
+	if (!img) {
+		perror("XCreateImage");
+		exit(1);
+	}
+	return(img);
+}
+
+init_image_conversion()
+{
+	display_depth = DefaultDepth(mydisplay, DefaultScreen(mydisplay));
+	switch (display_depth) {
+	case 24:
+		convert_function = convert_image_depth24;
+		break;
+	default:
+		fprintf(stderr,
+"error: fc-lcdemu has not been adapted for X11 depth != 24, yours is %d\n",
+			display_depth);
+		exit(1);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lcdemu/xrm.c	Wed Mar 14 18:16:45 2018 +0000
@@ -0,0 +1,97 @@
+/*
+ * LCDemu based on HECterm by the same author
+ * Xrm functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/Xutil.h>
+#include "globals.h"
+
+static char appdefaults_pathname[] =
+		"/usr/local/share/freecalypso/lcdemu-defaults";
+
+load_resources()
+{
+	xrmquark_topclass = XrmStringToQuark("LCDemu");
+	xrmquark_topinstance = XrmStringToQuark(proginstancename);
+	xrmdb_defaults = XrmGetFileDatabase(appdefaults_pathname);
+	xrmdb_displayres =
+		XrmGetStringDatabase(XResourceManagerString(mydisplay));
+}
+
+/*
+ * The following function looks up a resource in all of our databases
+ * and returns a pointer (char *) to the value in a malloced buffer that
+ * can be freed when it is no longer needed.  My reading of X11R4
+ * documentation indicates that resource values returned from Xrm functions
+ * are not necessarily NUL-terminated (no claim is made that they are
+ * and XrmValue structure has a size field), which is why I copy to
+ * my own buffer and NUL-terminate it there.
+ *
+ * Returns NULL pointer if not found in any of the databases.
+ */
+char *
+xrm_lookup(instquarks, classquarks)
+	XrmQuark *instquarks, *classquarks;
+{
+	XrmRepresentation reptype;
+	XrmValue value;
+	register char *buf;
+
+	if (XrmQGetResource(xrmdb_cmdline, instquarks, classquarks, &reptype,
+	    &value))
+		goto found;
+	if (XrmQGetResource(xrmdb_displayres, instquarks, classquarks, &reptype,
+	    &value))
+		goto found;
+	if (XrmQGetResource(xrmdb_defaults, instquarks, classquarks, &reptype,
+	    &value))
+		goto found;
+	return(NULL);
+found:	buf = malloc(value.size + 1);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+	bcopy(value.addr, buf, value.size);
+	buf[value.size] = '\0';
+	return(buf);
+}
+
+parse_boolean_resource(str)
+	register char *str;
+{
+	if (!strcasecmp(str, "on") || !strcasecmp(str, "true") ||
+	    !strcasecmp(str, "yes"))
+		return(1);
+	if (!strcasecmp(str, "off") || !strcasecmp(str, "false") ||
+	    !strcasecmp(str, "no"))
+		return(0);
+	return(atoi(str));
+}
+
+get_boolean_resource(resource, def)
+	char *resource;
+	int def;
+{
+	XrmQuark instquarks[3], classquarks[3];
+	register char *cp;
+	register int i;
+
+	instquarks[0] = xrmquark_topinstance;
+	classquarks[0] = xrmquark_topclass;
+	classquarks[1] = instquarks[1] = XrmStringToQuark(resource);
+	instquarks[2] = classquarks[2] = NULLQUARK;
+	cp = xrm_lookup(instquarks, classquarks);
+	if (cp) {
+		i = parse_boolean_resource(cp);
+		free(cp);
+	} else
+		i = def;
+	return(i);
+}