Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include        <u.h>
#include        <libc.h>
#include        "compat.h"
#include        "kbd.h"
#include        "error.h"

#define Image   IMAGE
#include        <draw.h>
#include        <memdraw.h>
#include        <cursor.h>
#include        "screen.h"

enum
{
        CURSORDIM = 16
};

Memimage        *gscreen;
Point           ZP;
int             cursorver;
Point           cursorpos;

static Memimage         *back;
static Memimage         *conscol;
static Memimage         *curscol;
static Point            curpos;
static Memsubfont       *memdefont;
static Rectangle        flushr;
static Rectangle        window;
static int              h;
static int              w;

static Rectangle        cursorr;
static Point            offscreen;
static uchar            cursset[CURSORDIM*CURSORDIM/8];
static uchar            cursclr[CURSORDIM*CURSORDIM/8];
static int              cursdrawvers = -1;
static Memimage         *cursorset;
static Memimage         *cursorclear;
static Cursor           screencursor;

Cursor  arrow = {
        { -1, -1 },
        { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
          0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
          0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
          0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
        },
        { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
          0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
          0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
          0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
        },
};

void
screeninit(int x, int y, char *chanstr)
{
        Point p, q;
        char *greet;
        char buf[128];
        Memimage *grey;
        Rectangle r;
        int chan;

        cursorver = 0;

        memimageinit();
        chan = strtochan(chanstr);
        if(chan == 0)
                error("bad screen channel string");

        r = Rect(0, 0, x, y);
        gscreen = allocmemimage(r, chan);
        if(gscreen == nil){
                snprint(buf, sizeof buf, "can't allocate screen image: %r");
                error(buf);
        }

        offscreen = Pt(x + 100, y + 100);
        cursorr = Rect(0, 0, CURSORDIM, CURSORDIM);
        cursorset = allocmemimage(cursorr, GREY8);
        cursorclear = allocmemimage(cursorr, GREY1);
        if(cursorset == nil || cursorclear == nil){
                freememimage(gscreen);
                freememimage(cursorset);
                freememimage(cursorclear);
                gscreen = nil;
                cursorset = nil;
                cursorclear = nil;
                snprint(buf, sizeof buf, "can't allocate cursor images: %r");
                error(buf);
        }

        drawlock();

        /*
         * set up goo for screenputs
         */
        memdefont = getmemdefont();

        back = memwhite;
        conscol = memblack;

        /* a lot of work to get a grey color */
        curscol = allocmemimage(Rect(0,0,1,1), RGBA32);
        curscol->flags |= Frepl;
        curscol->clipr = gscreen->r;
        memfillcolor(curscol, 0xff0000ff);

        memfillcolor(gscreen, 0x444488FF);

        w = memdefont->info[' '].width;
        h = memdefont->height;

        window.min = addpt(gscreen->r.min, Pt(20,20));
        window.max.x = window.min.x + Dx(gscreen->r)*3/4-40;
        window.max.y = window.min.y + Dy(gscreen->r)*3/4-100;

        memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP, S);
        window = insetrect(window, 4);
        memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);

        /* a lot of work to get a grey color */
        grey = allocmemimage(Rect(0,0,1,1), CMAP8);
        grey->flags |= Frepl;
        grey->clipr = gscreen->r;
        memfillcolor(grey, 0xAAAAAAFF);
        memimagedraw(gscreen, Rect(window.min.x, window.min.y,
                        window.max.x, window.min.y+h+5+6), grey, ZP, nil, ZP, S);
        freememimage(grey);
        window = insetrect(window, 5);

        greet = " Plan 9 Console ";
        p = addpt(window.min, Pt(10, 0));
        q = memsubfontwidth(memdefont, greet);
        memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
        window.min.y += h+6;
        curpos = window.min;
        window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
        flushmemscreen(gscreen->r);

        drawunlock();

        setcursor(&arrow);
}

uchar*
attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
{
        *r = gscreen->r;
        *d = gscreen->depth;
        *chan = gscreen->chan;
        *width = gscreen->width;
        *softscreen = 1;

        return gscreen->data->bdata;
}

void
getcolor(ulong , ulong* pr, ulong* pg, ulong* pb)
{
        *pr = 0;
        *pg = 0;
        *pb = 0;
}

int
setcolor(ulong , ulong , ulong , ulong )
{
        return 0;
}

/*
 * called with cursor unlocked, drawlock locked
 */
void
cursordraw(Memimage *dst, Rectangle r)
{
        static uchar set[CURSORDIM*CURSORDIM], clr[CURSORDIM*CURSORDIM/8];
        static int ver = -1;
        int i, j, n;

        lock(&cursor);
        if(ver != cursorver){
                n = 0;
                for(i = 0; i < CURSORDIM*CURSORDIM/8; i += CURSORDIM/8){
                        for(j = 0; j < CURSORDIM; j++){
                                if(cursset[i + (j >> 3)] & (1 << (7 - (j & 7))))
                                        set[n] = 0xaa;
                                else
                                        set[n] = 0;
                                n++;
                        }
                }
                memmove(clr, cursclr, CURSORDIM*CURSORDIM/8);
                ver = cursorver;
                unlock(&cursor);
                loadmemimage(cursorset, cursorr, set, CURSORDIM*CURSORDIM);
                loadmemimage(cursorclear, cursorr, clr, CURSORDIM*CURSORDIM/8);
        }else
                unlock(&cursor);
        memimagedraw(dst, r, memwhite, ZP, cursorclear, ZP, SoverD);
        memimagedraw(dst, r, curscol, ZP, cursorset, ZP, SoverD);
}

/*
 * called with cursor locked, drawlock possibly unlocked
 */
Rectangle
cursorrect(void)
{
        Rectangle r;

        r.min.x = cursorpos.x + cursor.offset.x;
        r.min.y = cursorpos.y + cursor.offset.y;
        r.max.x = r.min.x + CURSORDIM;
        r.max.y = r.min.y + CURSORDIM;
        return r;
}

/*
 * called with cursor locked, drawlock possibly unlocked
 */
void
setcursor(Cursor* curs)
{
        cursorver++;
        memmove(cursset, curs->set, CURSORDIM*CURSORDIM/8);
        memmove(cursclr, curs->clr, CURSORDIM*CURSORDIM/8);
}

int
cursoron(int dolock)
{
        if(dolock)
                lock(&cursor);
        cursorpos = mousexy();
        if(dolock)
                unlock(&cursor);

        return 0;
}

void
cursoroff(int dolock)
{
        if(dolock)
                lock(&cursor);
        cursorpos = offscreen;
        if(dolock)
                unlock(&cursor);
}

void
blankscreen(int blank)
{
        USED(blank);
}

static void
screenflush(void)
{
        flushmemscreen(flushr);
        flushr = Rect(10000, 10000, -10000, -10000);
}

static void
addflush(Rectangle r)
{
        if(flushr.min.x >= flushr.max.x)
                flushr = r;
        else
                combinerect(&flushr, r);
}

static void
scroll(void)
{
        int o;
        Point p;
        Rectangle r;

        o = 8*h;
        r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
        p = Pt(window.min.x, window.min.y+o);
        memimagedraw(gscreen, r, gscreen, p, nil, p, S);
        r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
        memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
        flushmemscreen(gscreen->r);

        curpos.y -= o;
}

static void
screenputc(char *buf)
{
        Point p;
        int w, pos;
        Rectangle r;
        static int *xp;
        static int xbuf[256];

        if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
                xp = xbuf;

        switch(buf[0]){
        case '\n':
                if(curpos.y+h >= window.max.y)
                        scroll();
                curpos.y += h;
                screenputc("\r");
                break;
        case '\r':
                xp = xbuf;
                curpos.x = window.min.x;
                break;
        case '\t':
                p = memsubfontwidth(memdefont, " ");
                w = p.x;
                *xp++ = curpos.x;
                pos = (curpos.x-window.min.x)/w;
                pos = 8-(pos%8);
                r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
                memimagedraw(gscreen, r, back, back->r.min, memopaque, ZP, S);
                addflush(r);
                curpos.x += pos*w;
                break;
        case '\b':
                if(xp <= xbuf)
                        break;
                xp--;
                r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
                memimagedraw(gscreen, r, back, back->r.min, memopaque, ZP, S);
                addflush(r);
                curpos.x = *xp;
                break;
        default:
                p = memsubfontwidth(memdefont, buf);
                w = p.x;

                if(curpos.x >= window.max.x-w)
                        screenputc("\n");

                *xp++ = curpos.x;
                r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h);
                memimagedraw(gscreen, r, back, back->r.min, memopaque, ZP, S);
                memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
                addflush(r);
                curpos.x += w;
        }
}

void
screenputs(char *s, int n)
{
        int i;
        Rune r;
        char buf[4];

        drawlock();
        while(n > 0){
                i = chartorune(&r, s);
                if(i == 0){
                        s++;
                        --n;
                        continue;
                }
                memmove(buf, s, i);
                buf[i] = 0;
                n -= i;
                s += i;
                screenputc(buf);
        }
        screenflush();
        drawunlock();
}