ref: 2e592b5e00e8f2489eba725135e3aab33438a9c0
dir: /screen.c/
#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;
}
}
}