shithub: cursedfs

ref: 2e592b5e00e8f2489eba725135e3aab33438a9c0
dir: cursedfs/screen.c

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <event.h>
#include "fs.h"


Point p;	// unused?
Font *ourfont;						// VGA
Image *brush;						// For drawing the text
Rune *s = L"☺☹σπß";	// for testing
int bwidth = 4;						// border width of rio win
Rune ***sbuf, **ebuf;				// screen buffer, empty buffer
usize sheight = 25, swidth = 80;	// screen height, width
Lock slock;							// screen buffer lock

Channel	*mchan, *kbchan;			// mouse and kb rcvr chans for fs


int kbv;
int mv;
Alt alts[3]; 

/* Menus */
char *buttons[] = {"exit", 0};	// Maybe a refresh button?
Menu menu = { buttons };

// Clear the screen
// TODO - do we need to free the screen buffer?
void
clear(void)
{
	eresized(0);
}

// Put a rune on the screen (x,y)
// Returns nil or an error message
Rune*
putrune(Rune r, usize x, usize y)
{
	if(y >= sheight)
		return L"fail: y out of bounds";

	if(x >= swidth)
		return L"fail: x out of bounds";

	lock(&slock);

	(*sbuf)[y][x] = r;

	unlock(&slock);
	return nil;
}

// Put a string on the screen (y)
// Must be allocated string
// Returns nil or an error message
Rune*
putstring(Rune *s, usize y)
{
	if(y >= sheight)
		return L"fail: y out of bounds";

	lock(&slock);

	free((*sbuf)[y]);
	(*sbuf)[y] = s;
	

	unlock(&slock);
	return nil;
}

// Free a 2D buffer
void
freebuf(Rune **buf, usize height)
{
	int i;
	for(i = 0; i < height; i++)
		free(buf[i]);
	free(buf);
}


// Render the active buffer on a timer
void
renderbuf(void)
{
	int i;
	Point p;

	if((*sbuf) == nil)
		// No buffer, no problems
		return;

	lock(&slock);
	Point at = screen->r.min;
	for(i = 0; i < sheight; i++){
		p = runestringsize(ourfont, (*sbuf)[i]);
		runestring(
			screen, at, display->black, ZP,
		    ourfont, (*sbuf)[i]
		);
		at.y += p.y;
	}
	unlock(&slock);

	flushimage(display, 1);
}

// Handle resize events
void
eresized(int new)
{
	if(new && getwindow(display, Refnone) < 0)
		sysfatal("can't reattach to window");

	/* Store new screen coordinates for collision detection */
	p = Pt(Dx(screen->r), Dy(screen->r));

	/* Draw the background DWhite */
	draw(screen, insetrect(screen->r, bwidth), 
			allocimage(display, Rect(0, 0, 1, 1), 
			screen->chan, 1, DWhite), 
			nil, ZP
	);
}

// Initialize the screen buffer
void
initbuf(void)
{
	int y, x;

	p = runestringsize(ourfont, s);

	lock(&slock);
	sbuf = calloc(sheight, sizeof (Rune**));
	*sbuf = calloc(sheight, sizeof (Rune*));
	ebuf = calloc(sheight, sizeof (Rune*));
	for(y = 0; y < sheight; y++){
		(*sbuf)[y] = calloc(swidth+1, sizeof (Rune));
		ebuf[y] = calloc(swidth+1, sizeof (Rune));
		for(x = 0; x < swidth; x++){
			(*sbuf)[y][x] = L'☺';
			ebuf[y][x] = L' ';
		}
	}
	unlock(&slock);
	//putstring(L"Quack☹☺", 2);
}

// Initialize the screen, spins forever
void
initscreen(void*)
{
	Event ev;
	int e, timer;

	/* Initiate graphics and mouse */
	//if(newwindow("-dx 100 -dy 100") < 0){
	//	fprint(2, "newwindow failed → %r");
	//	threadexitsall("newwindow failed → %r");
	//}
	if(initdraw(nil, "/lib/font/bit/vga/unicode.font", "cursedfs") < 0){
		fprint(2, "initdraw failed → %r");
		threadexitsall("initdraw failed → %r");
	}
	ourfont = openfont(display, "/lib/font/bit/vga/unicode.font");

	einit(Emouse | Ekeyboard);

	// Timer in ms
	timer = etimer(0, 15);

	/* Simulate a resize event to draw the background
	 * and acquire the screen dimensions */


	initbuf();

	// Set the screen size (after initbuf)
	//echo resize -dx 100 -dy 100 > /dev/wctl
	int fd;
	char *str;
	fd = open("/dev/wctl", OWRITE);
	usize width = (ourfont->width * swidth) + 2*bwidth +1;
	usize height = (ourfont->height * sheight) + 2*bwidth +1;
	str = smprint("resize -dx %ld -dy %ld\n", width, height);
	int out = write(fd, str, strlen(str));
	if(out < 1)
		sysfatal("err: /dev/wctl write failed → %r");
	close(fd);
	free(str);

	eresized(0);

	/* Main event loop */

	//kbv = calloc(1, sizeof (int));
	//mv  = calloc(1, sizeof (int));
	//memset(&alts, 0, sizeof alts);
	alts[0].c = mchan;
	alts[0].v = &mv;
	alts[0].op = CHANSND;
	alts[1].c = kbchan;
	alts[1].v = &kbv;
	alts[1].op = CHANSND;
	alts[2].op = CHANEND;

	for(;;){
		e = event(&ev);

		/* If there is a mouse event, the rightmost button
		 * pressed and the first menu option selected
		 * then exit.. */

		char kbdc;
		if(e == timer){
			// Render the screen buffer on ticks (top prio)
			eresized(0);
			renderbuf();

		}else if(e == Ekeyboard){
			kbdc = ev.kbdc;
			// Alt to optionally send if getch channel is listening
			kbv = kbdc;
			//putstring(runesmprint(" %d", kbv), 2);
			
		}else if(e == Emouse){
			if((ev.mouse.buttons & 4) 
				&& (emenuhit(3, &ev.mouse, &menu) == 0)
			)
				threadexitsall(nil);

			// Alt to optionally send if getm channel is listening
			mv = ev.mouse.buttons;
		}
		/* « deadlocks » */
		switch(alt(alts)){
		case 0:
			break;
		case 1:
			break;
		default:
			break;
		}
		
	}
}