Plan 9 from Bell Labs’s /usr/web/sources/extra/i/gui.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "i.h"

// globals
Rectangle rmain;
Rectangle rctl;
Rectangle rprog;

static void setwinrects(int new);
static void	rawkeyboard(void* arg);
static void	rawmouse(void* arg);
static int	sendevmouse(int x, int y, int mtype);

enum {
	CTLHEIGHT = 65,	// height of control (menu and toolbar) window
	PROGHEIGHT = 24,	// height of  progress window
	NCLIPR = 10,
};

static Rectangle cliprstack[NCLIPR];
static int nclipr;

void
guiinit(void)
{
	setwinrects(0);
	if(proccreate(rawmouse, nil, STACKSIZESMALL) < 0)
		fatalerror("can't create io procs");
	if(proccreate(rawkeyboard, nil, STACKSIZESMALL) < 0)
		fatalerror("can't create io procs");
}

static void
setwinrects(int new)
{
	int x,y,w,h;

	// Refnone ok because rio backs up our window
	if(new && getwindow(display, Refnone) < 0)
		fatalerror("can't reattach to window");

	// pay no attention to config values of x,y,defaultwidth,defaultheight,
	// since the user has swept the area for i
	x = screen->r.min.x;
	y = screen->r.min.y;
	w = Dx(screen->r);
	h = Dy(screen->r);
	if(w < 150 || h < CTLHEIGHT+PROGHEIGHT+100)
		fatalerror("window too small");
	rctl = Rect(x, y, x + w, y + CTLHEIGHT);
	rmain = Rect(x, y + CTLHEIGHT, x + w, y + h);
	rprog = Rect(x, rmain.max.y, x + w, rmain.max.y);
	if(config.showprogress) {
		rmain.max.y -= PROGHEIGHT;
		rprog.min.y -= PROGHEIGHT;
	}
	nclipr = 0;
	cliprstack[nclipr++] = screen->clipr;
}

// Change screen's clipr to r, saving old value in clipr stack
void
pushclipr(Rectangle r)
{
	assert(nclipr < NCLIPR);
	cliprstack[nclipr++] =  screen->clipr;
	replclipr(screen, 0, r);
}

// Replace screen's clipr to r, without changing clipr stack
void
replaceclipr(Rectangle r)
{
	replclipr(screen, 0, r);
}

// Restore screen's clipr to saveclipr
void
popclipr()
{
	assert(nclipr > 0);
	replclipr(screen, 0, cliprstack[--nclipr]);
}

Image*
makepopup(int width, int height)
{
	int	x;
	int	y;
	Rectangle	r;
	Image*	popupwin;

	x = rmain.min.x + (Dx(rmain) - width)/2;
	if(x < 0)
		x = 0;
	y = rmain.min.y + (Dy(rmain) - height)/2;
	if(y < 0)
		y = 0;
	r = Rect(x, y, x + width, y + height);
	popupwin = allocwindow(screen->screen, r, Refbackup, DGrey);
	return popupwin;
}

static void
rawkeyboard(void* arg)
{
	int	fd;
	int	ctl;
	int	i;
	Rune	r;
	int	n;
	int	k;
	int	nutf;
	EV	ev;
	char	buf[10];

	USED(arg);
	meminit(GRnone);
	fd = open("/dev/cons", OREAD);
	ctl = open("/dev/consctl", OWRITE|OCEXEC);
	if(fd < 0 || ctl < 0)
		fatalerror("can't open raw console");
	write(ctl, "rawon", 5);
	i = 0;
	while(1) {
		n = read(fd, buf+i, sizeof(buf) - i);
		if(n < 1)
			break;
		i += n;
		while(i > 0 && fullrune(buf, i)) {
			nutf = chartorune(&r, buf);
			k = r;
			switch(k) {
			case 128:
				k = Kdown;
				break;
			case 206:
				k = Kup;
				break;
			case 205:
				k = Khome;
				break;
			}
			ev = evkey(k);
			if(send(evchan, &ev) < 0)
				return;
			memmove(buf, buf+nutf, i-nutf);
			i -= nutf;
		}
	}
}

static void
rawmouse(void* arg)
{
	int	fd;
	int	n;
	int	xold;
	int	yold;
	int	bold;
	int	x;
	int	y;
	int	b;
	int	domoved;
	EV	ev;
	char	buf[1+4*12];

	USED(arg);
	meminit(GRnone);
	fd = open("/dev/mouse", OREAD);
	if(fd < 0)
		fatalerror("no mouse");
	xold = -1;
	yold = -1;
	bold = 0;
	while(1) {
		n = read(fd, buf, sizeof(buf));
		if(n <= 0)
			break;
		if(buf[0] == 'r') {
			setwinrects(1);
			ev.tag = EVresizetag;
			if(send(evchan, &ev) < 0)
				return;
			continue;
		}
		if(buf[0] != 'm' || n != sizeof(buf))
			continue;
		x = atoi(buf+1+0*12);
		y = atoi(buf+1+1*12);
		b = (atoi(buf+1+2*12))&7;
		domoved = (x != xold || y != yold);
		if(b == 0) {
			if(bold&1)
				if(sendevmouse(xold, yold, Mlbuttonup) < 0)
					return;
			if(bold&2)
				if(sendevmouse(xold, yold, Mmbuttonup) < 0)
					return;
			if(bold&4)
				if(sendevmouse(xold, yold, Mrbuttonup) < 0)
					return;
		}
		else {
			if(b&1) {
				if(bold&1) {
					if(sendevmouse(x, y, Mldrag) < 0)
						return;
					domoved = 0;
				}
				else {
					if(domoved) {
						if(sendevmouse(x, y, Mmove) < 0)
							return;
						domoved = 0;
					}
					if(sendevmouse(x, y, Mlbuttondown) < 0)
						return;
				}
			}
			if(b&2) {
				if(bold&2) {
					if(sendevmouse(x, y, Mmdrag) < 0)
						return;
					domoved = 0;
				}
				else {
					if(domoved) {
						if(sendevmouse(x, y, Mmove) < 0)
							return;
						domoved = 0;
					}
					if(sendevmouse(x, y, Mmbuttondown) < 0)
						return;
				}
			}
			if(b&4) {
				if(bold&4) {
					if(sendevmouse(x, y, Mrdrag) < 0)
						return;
					domoved = 0;
				}
				else {
					if(domoved) {
						if(sendevmouse(x, y, Mmove) < 0)
							return;
						domoved = 0;
					}
					if(sendevmouse(x, y, Mrbuttondown) < 0)
						return;
				}
			}
		}
		if(domoved)
			if(sendevmouse(x, y, Mmove) < 0)
				return;
		xold = x;
		yold = y;
		bold = b;
	}
}

static int
sendevmouse(int x, int y, int mtype)
{
	EV ev;

	ev = evmouse(Pt(x,y), mtype);
	return send(evchan, &ev);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.