672 lines · 12.4 KB · C
RawDownload
#include "u.h"#include "lib.h"#include "dat.h"#include "fns.h"#include "error.h" #include <draw.h>#include <memdraw.h>#include <keyboard.h>#include <cursor.h>#include "screen.h" #undef long#undef ulong #include <linux/fb.h>#include <linux/input.h> uchar*		fbp;Memimage*	screenimage;Memimage*	backbuf;Rectangle	screenr;char*		snarfbuf;struct fb_fix_screeninfo finfo;struct fb_var_screeninfo vinfo;int		*eventfds = NULL;int		neventfds;Point		mousexy;char		shift_state;int		ttyfd;char*		tty;char		hidden;int		devicesfd;ulong		chan;int		depth; #include <sys/ioctl.h>#include <sys/mman.h>#include <limits.h> #include <fcntl.h>#include <termios.h>#include <poll.h>#include <sys/ioctl.h>#include <linux/keyboard.h>#include <signal.h> #include <termios.h> #define ulong p9_ulong int code2key[] = {	Kesc, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\x08',	'\x09', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',	Kctl, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', Kshift,	'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', Kshift, '*', Kalt,	' ', Kcaps, KF|1, KF|2, KF|3, KF|4, KF|5, KF|6, KF|7, KF|8, KF|9, KF|10,	Knum, Kscroll,	'7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.',}; int code2key_shift[] = {	Kesc, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\x08',	'\x09', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',	Kctl, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\"', '~', Kshift,	'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', Kshift, '*', Kalt,	' ', Kcaps, KF|1, KF|2, KF|3, KF|4, KF|5, KF|6, KF|7, KF|8, KF|9, KF|10,	Knum, Kscroll,	'7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.',}; Memimage *gscreen;char *snarfbuf = nil; int onevent(struct input_event*);void termctl(uint32_t o, int or);void ctrlc(int sig); void_fbput(Memimage *m, Rectangle r) {	int y; 	for (y = r.min.y; y < r.max.y; y++){		long loc = y * finfo.line_length + r.min.x * depth;		void *ptr = m->data->bdata + y * m->width * 4 + r.min.x * depth; 		memcpy(fbp + loc, ptr, Dx(r) * depth);	}} Memimage*fbattach(int fbdevidx){	Rectangle r;	char devname[64];	size_t size;	int fd; 	/*	 * Connect to /dev/fb0	 */	snprintf(devname, sizeof(devname) - 1, "/dev/fb%d", fbdevidx);	if ((fd = open(devname, O_RDWR)) < 0)		goto err; 	if (ioctl(fd, FBIOGET_VSCREENINFO, &(vinfo)) < 0)		goto err; 	switch (vinfo.bits_per_pixel) {	case 32:		chan = XRGB32;		depth = 4;		break;	case 16:		chan = RGB16;		depth = 2;		break;	default:		goto err;	} 	if (ioctl(fd, FBIOGET_FSCREENINFO, &(finfo)) < 0)		goto err; 	size = vinfo.yres_virtual * finfo.line_length;	if ((fbp = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0)) < 0)		goto err;	/*	 * Figure out underlying screen format.	 */	r = Rect(0, 0, vinfo.xres_virtual, vinfo.yres_virtual); 	screenr = r; 	screenimage = allocmemimage(r, chan);	backbuf = allocmemimage(r, chan);	return backbuf; err:	return nil;} inteventattach(){	char eventfile[PATH_MAX] = "";	char line[PATH_MAX];	FILE *devices;	char *ptr; 	neventfds = 0;	devices = fopen("/proc/bus/input/devices", "r");	if (devices == NULL)		return -1;	while (fgets(line, sizeof(line)-1, devices) != NULL)		if (line[0] == 'H') {			ptr = strstr(line, "event");			if (ptr == NULL)				continue;			ptr[strcspn(ptr, " \r\n")] = '\0';			snprintf(eventfile, sizeof(eventfile)-1, "/dev/input/%s", ptr);			neventfds++;			eventfds = realloc(eventfds, neventfds * sizeof(int));			eventfds[neventfds-1] = open(eventfile, O_RDONLY);			if (eventfds[neventfds-1] < 0)				neventfds--;		}	fclose(devices); 	if (neventfds == 0)		return -1;	return 1;} voidflushmemscreen(Rectangle r){	int x, y, i;	Point p;	long fbloc;	int x2, y2; 	if (rectclip(&r, screenimage->r) == 0)		return;	if (Dx(r) == 0 || Dy(r) == 0)		return; 	assert(!canqlock(&drawlock)); 	memimagedraw(screenimage, r, backbuf, r.min, nil, r.min, S); 	if (hidden != 0)		return; 	p = mousexy; 	// draw cursor	for (x = 0; x < 16; x++) {		x2 = x + cursor.offset.x; 		if ((p.x + x2) < 0)			continue; 		if ((p.x + x2) >= screenimage->r.max.x)			break; 		for (y = 0; y < 16; y++) {			y2 = y + cursor.offset.y; 			if ((p.y + y2) < 0)				continue; 			if ((p.y + y2) >= screenimage->r.max.y)				break; 			i = y * 2 + x / 8;			fbloc = ((p.y+y2) * screenimage->r.max.x + (p.x+x2)) * depth; 			if (cursor.clr[i] & (128 >> (x % 8))) {				switch (depth) {				case 2:					*((uint16_t*)(screenimage->data->bdata + fbloc)) = 0xFFFF;					break;				case 4:					*((uint32_t*)(screenimage->data->bdata + fbloc)) = 0xFFFFFFFF;					break;				}			} 			if (cursor.set[i] & (128 >> (x % 8))) {				switch (depth) {				case 2:					*((uint16_t*)(screenimage->data->bdata + fbloc)) = 0x0000;					break;				case 4:					*((uint32_t*)(screenimage->data->bdata + fbloc)) = 0xFF000000;					break;				}			}		}	} 	_fbput(screenimage, r);} static voidfbproc(void *v){	struct input_event data;	char buf[32];	struct pollfd *pfd;	int r;	int ioctlarg; 	pfd = calloc(3, sizeof(struct pollfd));	pfd[0].fd = ttyfd; // for virtual console switches	pfd[0].events = POLLPRI;	pfd[1].fd = 0; // stdin goes to nowhere	pfd[1].events = POLLIN;	pfd[2].fd = open("/proc/bus/input/devices", O_RDONLY); // input hotplug	if (pfd[2].fd < 0)		panic("cannot open /proc/bus/input/devices: %r");	pfd[2].events = POLLIN; TOP:	while(read(pfd[2].fd, buf, 31) > 0); 	pfd = realloc(pfd, sizeof(struct pollfd) * (neventfds + 3));	for (r = 0; r < neventfds; r++) {		pfd[r+3].fd = eventfds[r];		pfd[r+3].events = POLLIN;	} 	for(;;) {		shift_state = 6;		if (ioctl(0, TIOCLINUX, &shift_state) < 0)			panic("ioctl TIOCLINUX 6: %r"); 		r = poll(pfd, 3+neventfds, -1);		if (r < 0)			oserror();		if (pfd[0].revents & POLLPRI) {			if ((r = read(ttyfd, buf, 31)) <= 0)				panic("ttyfd read: %r");			buf[r] = '\0';			if (strcmp(buf, tty) == 0) {				hidden = 0;				printf("\e[?25l");				fflush(stdout);				qlock(&drawlock);				flushmemscreen(gscreen->clipr);				qunlock(&drawlock);			}			else				hidden = 1;			close(ttyfd);			ttyfd = open("/sys/class/tty/tty0/active", O_RDONLY);			if (ttyfd < 0)				panic("cannot open tty active fd: %r");			pfd[0].fd = ttyfd;			read(ttyfd, buf, 0);		}		if (pfd[1].revents & POLLIN)			read(pfd[1].fd, buf, 31);		if (pfd[2].revents & POLLIN) {			for (r = 0; r < neventfds; r++)				close(eventfds[r]);			if(eventattach() < 0) {				panic("cannot open event files: %r");			}			goto TOP;		}		for (r = 0; r < neventfds; r++)			if (pfd[r+3].revents & POLLIN) {				if (read(pfd[r+3].fd, &data, sizeof(data)) != sizeof(data))					panic("eventfd read: %r");				if (onevent(&data) == 0) {					ioctlarg = 15;					if (ioctl(0, TIOCLINUX, &ioctlarg) != 0) {						ioctlarg = 4;						ioctl(0, TIOCLINUX, &ioctlarg);						qlock(&drawlock);						flushmemscreen(gscreen->clipr);						qunlock(&drawlock);					} else {						write(1, "\033[9;30]", 7);					}				}			}	} 	printf("\e[?25h");	fflush(stdout);	termctl(ECHO, 1);	free(pfd);} voidscreensize(Rectangle r, ulong chan){	gscreen = backbuf;	gscreen->clipr = ZR;} voidscreeninit(void){	int r;	char buf[1]; 	// set up terminal	printf("\e[?25l");	fflush(stdout);	termctl(~(ICANON|ECHO), 0);	signal(SIGINT, ctrlc); 	memimageinit(); 	// tty switching	ttyfd = open("/sys/class/tty/tty0/active", O_RDONLY);	if (ttyfd >= 0) {		tty = malloc(32);		r = read(ttyfd, tty, 31);		if (r >= 0)			tty[r] = '\0';		else			tty[0] = '\0';		close(ttyfd);		ttyfd = open("/sys/class/tty/tty0/active", O_RDONLY);	}	if (ttyfd < 0)		panic("cannot open tty active fd: %r");	read(ttyfd, buf, 0);	hidden = 0; 	if(fbattach(0) == nil) {		panic("cannot open framebuffer: %r");	} 	if(eventattach() < 0) {		panic("cannot open event files: %r");	} 	screensize(screenr, chan);	if (gscreen == nil)		panic("screensize failed"); 	gscreen->clipr = screenr;	kproc("fbdev", fbproc, nil); 	qlock(&drawlock);	terminit();	flushmemscreen(gscreen->clipr);	qunlock(&drawlock);} Memdata*attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen){	*r = gscreen->clipr;	*chan = gscreen->chan;	*depth = gscreen->depth;	*width = gscreen->width;	*softscreen = 1; 	gscreen->data->ref++;	return gscreen->data;} voidgetcolor(ulong i, ulong *r, ulong *g, ulong *b){	ulong v;		v = cmap2rgb(i);	*r = (v>>16)&0xFF;	*g = (v>>8)&0xFF;	*b = v&0xFF;} voidsetcolor(ulong i, ulong r, ulong g, ulong b){	/* no-op */	return;} char*clipread(void){	if(snarfbuf)		return strdup(snarfbuf);	return nil;} intclipwrite(char *buf){	if(snarfbuf)		free(snarfbuf);	snarfbuf = strdup(buf);	return 0;} voidguimain(void){	cpubody();} voidtermctl(uint32_t o, int or){	struct termios t; 	tcgetattr(0, &t);	if (or)		t.c_lflag |= o;	else		t.c_lflag &= o;	tcsetattr(0, TCSANOW, &t);} voidctrlc(int sig) {} intonevent(struct input_event *data){	Rectangle old, new;	ulong msec;	static int buttons;	static Point coord;	static char touched;	static Point startmousept;	static Point startpt;	int key;	static ulong lastmsec = 0; 	if (hidden != 0)		return -1; 	msec = ticks(); 	old.min = mousexy;	old.max = addpt(old.min, Pt(16, 16)); 	buttons &= ~0x18; 	switch(data->type) {	case 3:		switch(data->code) {		case 0:			coord.x = data->value;			break;		case 1:			coord.y = data->value;			break;		case 0x18:

Lines 1–500 of 672.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t