ref: 3c761dea5de8d7b2bce06a39c51c7885f08910de
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 */ kbchan = chancreate(sizeof (int), 10); mchan = chancreate(sizeof (int), 10); //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; }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; } */ } }