Annotation of lucent/sys/src/9/port/devbit.c, revision 1.1.1.1

1.1       root        1: #include       "u.h"
                      2: #include       "../port/lib.h"
                      3: #include       <libg.h>
                      4: #include       <gnot.h>
                      5: #include       "mem.h"
                      6: #include       "dat.h"
                      7: #include       "fns.h"
                      8: #include       "../port/error.h"
                      9: 
                     10: #include       "devtab.h"
                     11: 
                     12: #include       "screen.h"
                     13: 
                     14: /*
                     15:  * Some monochrome screens are reversed from what we like:
                     16:  * We want 0's bright and 1's dark.
                     17:  * Indexed by an Fcode, these compensate for the source bitmap being wrong
                     18:  * (exchange S rows) and destination (exchange D columns and invert result)
                     19:  */
                     20: int flipS[] = {
                     21:        0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD,
                     22:        0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF
                     23: };
                     24: 
                     25: int flipD[] = {
                     26:        0xF, 0xD, 0xE, 0xC, 0x7, 0x5, 0x6, 0x4,
                     27:        0xB, 0x9, 0xA, 0x8, 0x3, 0x1, 0x2, 0x0, 
                     28: };
                     29: 
                     30: int flipping;  /* are flip tables being used to transform Fcodes? */
                     31: 
                     32: /*
                     33:  * Device (#b/bitblt) is exclusive use on open, so no locks are necessary
                     34:  * for i/o
                     35:  */
                     36: 
                     37: /*
                     38:  * Arena is a word containing N, followed by a pointer to the Arena,
                     39:  * followed by a pointer to the Bitmap, followed by N words.
                     40:  * The bitmap pointer is zero if block is free.
                     41:  * bit.map is an array of pointers to GBitmaps.  The GBitmaps are
                     42:  * freed individually and their corresponding entries in bit.map are zeroed.
                     43:  * The index into bit.map is the Bitmap id as seen in libg.  Subfonts and
                     44:  * fonts are handled similarly.
                     45:  */
                     46: 
                     47: typedef struct Arena   Arena;
                     48: struct Arena
                     49: {
                     50:        ulong   *words;         /* storage */
                     51:        ulong   *wfree;         /* pointer to next free word */
                     52:        ulong   nwords;         /* total in arena */
                     53:        int     nbusy;          /* number of busy blocks */
                     54: };
                     55: 
                     56: typedef struct BSubfont BSubfont;
                     57: struct BSubfont
                     58: {
                     59:        GSubfont;
                     60:        int     ref;            /* number of times this subfont is open */
                     61:        ulong   qid[2];         /* unique id used as a cache tag */
                     62: };
                     63: 
                     64: extern GSubfont        *defont;
                     65:        BSubfont        *bdefont;
                     66:        BSubfont bdefont0;
                     67: 
                     68: 
                     69: struct
                     70: {
                     71:        Ref;
                     72:        QLock;
                     73:        GBitmap **map;          /* indexed array */
                     74:        int     nmap;           /* number allocated */
                     75:        GFont   **font;         /* indexed array */
                     76:        int     nfont;          /* number allocated */
                     77:        BSubfont**subfont;      /* indexed array */
                     78:        int     nsubfont;       /* number allocated */
                     79:        Arena   *arena;         /* array */
                     80:        int     narena;         /* number allocated */
                     81:        int     mouseopen;      /* flag: mouse open */
                     82:        int     bitbltopen;     /* flag: bitblt open */
                     83:        int     bid;            /* last allocated bitmap id */
                     84:        int     subfid;         /* last allocated subfont id */
                     85:        int     cacheid;        /* last cached subfont id */
                     86:        int     fid;            /* last allocated font id */
                     87:        int     init;           /* freshly opened; init message pending */
                     88:        int     rid;            /* read bitmap id */
                     89:        int     rminy;          /* read miny */
                     90:        int     rmaxy;          /* read maxy */
                     91:        int     mid;            /* colormap read bitmap id */
                     92: }bit;
                     93: 
                     94: #define        DMAP    16              /* delta increase in size of arrays */
                     95: #define        FREE    0x80000000
                     96: 
                     97: void   bitcompact(void);
                     98: int    bitalloc(Rectangle, int);
                     99: void   bitfree(GBitmap*);
                    100: void   fontfree(GFont*);
                    101: void   subfontfree(BSubfont*, int);
                    102: void   arenafree(Arena*);
                    103: void   bitstring(GBitmap*, Point, GFont*, uchar*, long, Fcode);
                    104: void   bitloadchar(GFont*, int, GSubfont*, int);
                    105: extern GBitmap gscreen;
                    106: 
                    107: typedef struct Mouseinfo       Mouseinfo;
                    108: typedef struct Cursorinfo      Cursorinfo;
                    109: 
                    110: struct Mouseinfo{
                    111:        /*
                    112:         * First three fields are known in some l.s's
                    113:         */
                    114:        int     dx;
                    115:        int     dy;
                    116:        int     track;          /* l.s has updated dx & dy */
                    117:        Mouse;
                    118:        int     redraw;         /* update cursor on screen */
                    119:        ulong   counter;        /* increments every update */
                    120:        ulong   lastcounter;    /* value when /dev/mouse read */
                    121:        Rendez  r;
                    122: };
                    123: 
                    124: struct Cursorinfo{
                    125:        Cursor;
                    126:        Lock;
                    127:        int     visible;        /* on screen */
                    128:        Rectangle r;            /* location */
                    129: };
                    130: 
                    131: Mouseinfo      mouse;
                    132: Cursorinfo     cursor;
                    133: Cursor         curs;
                    134: int            mouseshifted;
                    135: int            mousetype;
                    136: int            mouseswap;
                    137: int            islittle;
                    138: int            hwcurs;
                    139: 
                    140: Cursor arrow =
                    141: {
                    142:        {-1, -1},
                    143:        {0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0x00,
                    144:         0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xE0,
                    145:         0xE7, 0xF0, 0xE3, 0xF8, 0xC1, 0xFC, 0x00, 0xFE,
                    146:         0x00, 0x7F, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08,
                    147:        },
                    148:        {0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00,
                    149:         0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0,
                    150:         0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C,
                    151:         0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00,
                    152:        }
                    153: };
                    154: 
                    155: ulong setbits[16];
                    156: GBitmap        set =
                    157: {
                    158:        setbits,
                    159:        0,
                    160:        1,
                    161:        0,
                    162:        {0, 0, 16, 16},
                    163:        {0, 0, 16, 16}
                    164: };
                    165: 
                    166: ulong clrbits[16];
                    167: GBitmap        clr =
                    168: {
                    169:        clrbits,
                    170:        0,
                    171:        1,
                    172:        0,
                    173:        {0, 0, 16, 16},
                    174:        {0, 0, 16, 16}
                    175: };
                    176: 
                    177: ulong cursorbackbits[16*4];
                    178: GBitmap cursorback =
                    179: {
                    180:        cursorbackbits,
                    181:        0,
                    182:        1,
                    183:        0,
                    184:        {0, 0, 16, 16},
                    185:        {0, 0, 16, 16}
                    186: };
                    187: 
                    188: void   Cursortocursor(Cursor*);
                    189: int    mousechanged(void*);
                    190: 
                    191: enum{
                    192:        Qdir,
                    193:        Qbitblt,
                    194:        Qmouse,
                    195:        Qmousectl,
                    196:        Qscreen,
                    197: };
                    198: 
                    199: Dirtab bitdir[]={
                    200:        "bitblt",       {Qbitblt},      0,                      0666,
                    201:        "mouse",        {Qmouse},       0,                      0666,
                    202:        "mousectl",     {Qmousectl},    0,                      0220,
                    203:        "screen",       {Qscreen},      0,                      0444,
                    204: };
                    205: 
                    206: #define        NBIT    (sizeof bitdir/sizeof(Dirtab))
                    207: #define        NINFO   8192    /* max chars per subfont; sanity check only */
                    208: #define        HDR     3
                    209: 
                    210: void
                    211: lockedupdate(void)
                    212: {
                    213:        qlock(&bit);
                    214:        if(waserror()){
                    215:                qunlock(&bit);
                    216:                return;
                    217:        }
                    218:        screenupdate();
                    219:        qunlock(&bit);
                    220:        poperror();
                    221: }
                    222: 
                    223: void
                    224: bitfreeup(void)
                    225: {
                    226:        int i;
                    227:        BSubfont *s;
                    228: 
                    229:        /* free unused subfonts and compact */
                    230:        for(i=0; i<bit.nsubfont; i++){
                    231:                s = bit.subfont[i];
                    232:                if(s && s!=bdefont && s->ref==0){
                    233:                        s->ref = 1;
                    234:                        s->qid[0] = ~0; /* force cleanup */
                    235:                        subfontfree(s, i);
                    236:                }
                    237:        }
                    238:        bitcompact();
                    239: }
                    240: 
                    241: void*
                    242: bitmalloc(ulong n)
                    243: {
                    244:        void *p;
                    245: 
                    246:        p = malloc(n);
                    247:        if(p)
                    248:                return p;
                    249:        bitfreeup();
                    250:        return malloc(n);
                    251: }
                    252: 
                    253: void
                    254: bitdebug(void)
                    255: {
                    256:        int i;
                    257:        long l;
                    258:        Arena *a;
                    259: 
                    260:        l = 0;
                    261:        for(i=0; i<bit.narena; i++){
                    262:                a = &bit.arena[i];
                    263:                if(a->words){
                    264:                        l += a->nwords;
                    265:                        print("%d: %ld bytes used; %ld total\n", i,
                    266:                                (a->wfree-a->words)*sizeof(ulong),
                    267:                                a->nwords*sizeof(ulong));
                    268:                }
                    269:        }
                    270:        print("arena: %ld bytes\n", l*sizeof(ulong));
                    271:        l = 0;
                    272:        for(i=0; i<bit.nmap; i++)
                    273:                if(bit.map[i])
                    274:                        l++;
                    275:        print("%d bitmaps ", l);
                    276:        l = 0;
                    277:        for(i=0; i<bit.nfont; i++)
                    278:                if(bit.font[i])
                    279:                        l++;
                    280:        print("%d fonts ", l);
                    281:        l = 0;
                    282:        for(i=0; i<bit.nsubfont; i++)
                    283:                if(bit.subfont[i]){
                    284:                        print("%d: %lux %lux ", i, bit.subfont[i]->qid[0], bit.subfont[i]->qid[1]);
                    285:                        l++;
                    286:                }
                    287:        print("%d subfonts\n", l);
                    288: }
                    289: 
                    290: void
                    291: bitreset(void)
                    292: {
                    293:        int ws;
                    294:        ulong r;
                    295:        Arena *a;
                    296: 
                    297:        if(!conf.monitor)
                    298:                return;
                    299: 
                    300:        memmove(&bdefont0, defont, sizeof(*defont));
                    301:        bdefont = &bdefont0;
                    302:        bit.map = smalloc(DMAP*sizeof(GBitmap*));
                    303:        bit.nmap = DMAP;
                    304:        getcolor(0, &r, &r, &r);
                    305:        if(r == 0)
                    306:                flipping = 1;
                    307:        bit.bid = -1;
                    308:        bit.subfid = -1;
                    309:        bit.fid = -1;
                    310:        bit.cacheid = -1;
                    311:        bit.font = smalloc(DMAP*sizeof(GFont*));
                    312:        bit.nfont = DMAP;
                    313:        bit.subfont = smalloc(DMAP*sizeof(BSubfont*));
                    314:        bit.nsubfont = DMAP;
                    315:        bit.arena = smalloc(DMAP*sizeof(Arena));
                    316:        bit.narena = DMAP;
                    317:        a = &bit.arena[0];
                    318:        /*
                    319:         * Somewhat of a heuristic: start with three screensful and
                    320:         * allocate single screensful dynamically if needed.
                    321:         */
                    322: 
                    323:        ws = BI2WD>>gscreen.ldepth;     /* pixels per word */
                    324:        a->nwords = 3*(HDR + gscreen.r.max.y*gscreen.r.max.x/ws);
                    325:        a->words = xalloc(a->nwords*sizeof(ulong));
                    326:        if(a->words == 0){
                    327:                /* try again */
                    328:                print("bitreset: allocating only 1 screenful\n");
                    329:                a->nwords /= 3;
                    330:                a->words = a->words = xalloc(a->nwords*sizeof(ulong));
                    331:                if(a->words == 0)
                    332:                        panic("bitreset");
                    333:        }
                    334:        a->wfree = a->words;
                    335:        a->nbusy = 1;   /* keep 0th arena from being freed */
                    336:        Cursortocursor(&arrow);
                    337: }
                    338: 
                    339: /*
                    340:  *  screen bit depth changed, reset backup map for cursor
                    341:  */
                    342: void
                    343: bitdepth(void)
                    344: {
                    345:        cursoroff(1);
                    346:        if(gscreen.ldepth > 3)
                    347:                cursorback.ldepth = 0;
                    348:        else{
                    349:                cursorback.ldepth = gscreen.ldepth;
                    350:                cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5;
                    351:        }
                    352:        cursoron(1);
                    353: }
                    354: 
                    355: void
                    356: bitinit(void)
                    357: {
                    358:        if(!conf.monitor)
                    359:                return;
                    360:        if(gscreen.ldepth > 3)
                    361:                cursorback.ldepth = 0;
                    362:        else{
                    363:                cursorback.ldepth = gscreen.ldepth;
                    364:                cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5;
                    365:        }
                    366:        cursoron(1);
                    367: }
                    368: 
                    369: Chan*
                    370: bitattach(char *spec)
                    371: {
                    372:        if(!conf.monitor)
                    373:                error(Egreg);
                    374:        return devattach('b', spec);
                    375: }
                    376: 
                    377: Chan*
                    378: bitclone(Chan *c, Chan *nc)
                    379: {
                    380:        if(!conf.monitor)
                    381:                error(Egreg);
                    382:        nc = devclone(c, nc);
                    383:        if(c->qid.path != CHDIR)
                    384:                incref(&bit);
                    385:        return nc;
                    386: }
                    387: 
                    388: int
                    389: bitwalk(Chan *c, char *name)
                    390: {
                    391:        if(!conf.monitor)
                    392:                error(Egreg);
                    393:        return devwalk(c, name, bitdir, NBIT, devgen);
                    394: }
                    395: 
                    396: void
                    397: bitstat(Chan *c, char *db)
                    398: {
                    399:        if(!conf.monitor)
                    400:                error(Egreg);
                    401:        devstat(c, db, bitdir, NBIT, devgen);
                    402: }
                    403: 
                    404: Chan*
                    405: bitopen(Chan *c, int omode)
                    406: {
                    407:        GBitmap *b;
                    408: 
                    409:        if(!conf.monitor)
                    410:                error(Egreg);
                    411:        switch(c->qid.path){
                    412:        case CHDIR:
                    413:                if(omode != OREAD)
                    414:                        error(Eperm);
                    415:                break;
                    416:        case Qmouse:
                    417:                lock(&bit);
                    418:                if(bit.mouseopen){
                    419:                        unlock(&bit);
                    420:                        error(Einuse);
                    421:                }
                    422:                bit.mouseopen = 1;
                    423:                bit.ref++;
                    424:                unlock(&bit);
                    425:                break;
                    426:        case Qbitblt:
                    427:                lock(&bit);
                    428:                if(bit.bitbltopen || bit.mouseopen){
                    429:                        unlock(&bit);
                    430:                        error(Einuse);
                    431:                }
                    432:                b = smalloc(sizeof(GBitmap));
                    433:                *b = gscreen;
                    434:                bit.map[0] = b;                 /* bitmap 0 is screen */
                    435:                bit.subfont[0] = bdefont;       /* subfont 0 is default */
                    436:                bit.subfont[0]->ref = 1;
                    437:                bit.subfont[0]->qid[0] = 0;
                    438:                bit.subfont[0]->qid[1] = 0;
                    439:                bit.bid = -1;
                    440:                bit.fid = -1;
                    441:                bit.subfid = -1;
                    442:                bit.cacheid = -1;
                    443:                bit.rid = -1;
                    444:                bit.mid = -1;
                    445:                bit.init = 0;
                    446:                bit.bitbltopen = 1;
                    447:                Cursortocursor(&arrow);
                    448:                unlock(&bit);
                    449:                break;
                    450:        default:
                    451:                incref(&bit);
                    452:        }
                    453:        c->mode = openmode(omode);
                    454:        c->flag |= COPEN;
                    455:        c->offset = 0;
                    456:        return c;
                    457: }
                    458: 
                    459: void
                    460: bitcreate(Chan *c, char *name, int omode, ulong perm)
                    461: {
                    462:        if(!conf.monitor)
                    463:                error(Egreg);
                    464:        USED(c, name, omode, perm);
                    465:        error(Eperm);
                    466: }
                    467: 
                    468: void
                    469: bitremove(Chan *c)
                    470: {
                    471:        if(!conf.monitor)
                    472:                error(Egreg);
                    473:        USED(c);
                    474:        error(Eperm);
                    475: }
                    476: 
                    477: void
                    478: bitwstat(Chan *c, char *db)
                    479: {
                    480:        if(!conf.monitor)
                    481:                error(Egreg);
                    482:        USED(c, db);
                    483:        error(Eperm);
                    484: }
                    485: 
                    486: void
                    487: bitclose(Chan *c)
                    488: {
                    489:        GBitmap *b, **bp, **ebp;
                    490:        BSubfont *s, **sp, **esp;
                    491:        GFont *f, **fp, **efp;
                    492: 
                    493:        if(!conf.monitor)
                    494:                error(Egreg);
                    495:        if(c->qid.path!=CHDIR && (c->flag&COPEN)){
                    496:                lock(&bit);
                    497:                if(c->qid.path == Qmouse)
                    498:                        bit.mouseopen = 0;
                    499:                if(c->qid.path == Qbitblt)
                    500:                        bit.bitbltopen = 0;
                    501:                if(--bit.ref == 0){
                    502:                        ebp = &bit.map[bit.nmap];
                    503:                        for(bp = bit.map; bp<ebp; bp++){
                    504:                                b = *bp;
                    505:                                if(b){
                    506:                                        bitfree(b);
                    507:                                        *bp = 0;
                    508:                                }
                    509:                        }
                    510:                        esp = &bit.subfont[bit.nsubfont];
                    511:                        for(sp=bit.subfont; sp<esp; sp++){
                    512:                                s = *sp;
                    513:                                if(s)
                    514:                                        subfontfree(s, sp-bit.subfont);
                    515:                                /* don't clear *sp: cached */
                    516:                        }
                    517:                        efp = &bit.font[bit.nfont];
                    518:                        for(fp=bit.font; fp<efp; fp++){
                    519:                                f = *fp;
                    520:                                if(f){
                    521:                                        fontfree(f);
                    522:                                        *fp = 0;
                    523:                                }
                    524:                        }
                    525:                }
                    526:                unlock(&bit);
                    527:        }
                    528: }
                    529: 
                    530: long
                    531: bitread(Chan *c, void *va, long n, ulong offset)
                    532: {
                    533:        uchar *p, *q;
                    534:        long miny, maxy, t, x, y;
                    535:        ulong l, nw, ws, rv, gv, bv;
                    536:        int off, j;
                    537:        Fontchar *i;
                    538:        GBitmap *src;
                    539:        BSubfont *s;
                    540:        static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
                    541: 
                    542:        if(!conf.monitor)
                    543:                error(Egreg);
                    544:        if(c->qid.path & CHDIR)
                    545:                return devdirread(c, va, n, bitdir, NBIT, devgen);
                    546: 
                    547:        if(c->qid.path == Qmouse){
                    548:                /*
                    549:                 * mouse:
                    550:                 *      'm'             1
                    551:                 *      buttons         1
                    552:                 *      point           8
                    553:                 *      msec            4
                    554:                 */
                    555:                if(n < 14)
                    556:                        error(Ebadblt);
                    557:                while(mousechanged(0) == 0)
                    558:                        sleep(&mouse.r, mousechanged, 0);
                    559:                lock(&cursor);
                    560:                p = va;
                    561:                p[0] = 'm';
                    562:                p[1] = mouseswap ? map[mouse.buttons&7] : mouse.buttons;
                    563:                BPLONG(p+2, mouse.xy.x);
                    564:                BPLONG(p+6, mouse.xy.y);
                    565:                BPLONG(p+10, TK2MS(MACHP(0)->ticks));
                    566:                mouse.lastcounter = mouse.counter;
                    567:                unlock(&cursor);
                    568:                return 14;
                    569:        }
                    570:        if(c->qid.path == Qscreen){
                    571:                if(offset==0){
                    572:                        if(n < 5*12)
                    573:                                error(Eio);
                    574:                        sprint(va, "%11d %11d %11d %11d %11d ",
                    575:                                gscreen.ldepth, gscreen.r.min.x,
                    576:                                gscreen.r.min.y, gscreen.r.max.x,
                    577:                                gscreen.r.max.y);
                    578:                        return 5*12;
                    579:                }
                    580:                ws = 1<<(3-gscreen.ldepth);     /* pixels per byte */
                    581:                l = (gscreen.r.max.x+ws-1)/ws - gscreen.r.min.x/ws;
                    582:                if(l == 0)
                    583:                        error(Ebadblt);
                    584:                t = offset-5*12;
                    585:                miny = t/l;     /* unsigned computation */
                    586:                maxy = (t+n)/l;
                    587:                if(miny >= gscreen.r.max.y)
                    588:                        return 0;
                    589:                if(maxy >= gscreen.r.max.y)
                    590:                        maxy = gscreen.r.max.y;
                    591:                n = 0;
                    592:                p = va;
                    593:                for(y=miny; y<maxy; y++){
                    594:                        q = (uchar*)gaddr(&gscreen, Pt(0, y));
                    595:                        memmove(p, q, l);
                    596:                        if(flipping)
                    597:                                /* is screen, so must be word aligned */
                    598:                                for(x=0; x<l; x+=sizeof(ulong),p+=sizeof(ulong))
                    599:                                        *(ulong*)p ^= ~0;
                    600:                        else
                    601:                                p += l;
                    602:                        n += l;
                    603:                }
                    604:                return n;
                    605:        }
                    606:        if(c->qid.path != Qbitblt)
                    607:                error(Egreg);
                    608: 
                    609:        qlock(&bit);
                    610:        if(waserror()){
                    611:                qunlock(&bit);
                    612:                nexterror();
                    613:        }
                    614:        p = va;
                    615:        /*
                    616:         * Fuss about and figure out what to say.
                    617:         */
                    618:        if(bit.init){
                    619:                /*
                    620:                 * init:
                    621:                 *      'I'             1
                    622:                 *      ldepth          1
                    623:                 *      rectangle       16
                    624:                 *      clip rectangle  16
                    625:                 *      font info       3*12
                    626:                 *      fontchars       6*(bdefont->n+1)
                    627:                 */
                    628:                if(n < 34)
                    629:                        error(Ebadblt);
                    630:                p[0] = 'I';
                    631:                p[1] = gscreen.ldepth;
                    632:                BPLONG(p+2, gscreen.r.min.x);
                    633:                BPLONG(p+6, gscreen.r.min.y);
                    634:                BPLONG(p+10, gscreen.r.max.x);
                    635:                BPLONG(p+14, gscreen.r.max.y);
                    636:                BPLONG(p+18, gscreen.clipr.min.x);
                    637:                BPLONG(p+22, gscreen.clipr.min.y);
                    638:                BPLONG(p+26, gscreen.clipr.max.x);
                    639:                BPLONG(p+30, gscreen.clipr.max.y);
                    640:                if(n >= 34+3*12+6*(bdefont->n+1)){
                    641:                        p += 34;
                    642:                        sprint((char*)p, "%11d %11d %11d ", bdefont->n,
                    643:                                bdefont->height, bdefont->ascent);
                    644:                        p += 3*12;
                    645:                        for(i=bdefont->info,j=0; j<=bdefont->n; j++,i++,p+=6){
                    646:                                BPSHORT(p, i->x);
                    647:                                p[2] = i->top;
                    648:                                p[3] = i->bottom;
                    649:                                p[4] = i->left;
                    650:                                p[5] = i->width;
                    651:                        }
                    652:                        n = 34+3*12+6*(bdefont->n+1);
                    653:                }else
                    654:                        n = 34;
                    655:                bit.init = 0;
                    656:        }else if(bit.bid > 0){
                    657:                /*
                    658:                 * allocate:
                    659:                 *      'A'             1
                    660:                 *      bitmap id       2
                    661:                 */
                    662:                if(n < 3)
                    663:                        error(Ebadblt);
                    664:                if(bit.bid<0 || bit.map[bit.bid]==0)
                    665:                        error(Ebadbitmap);
                    666:                p[0] = 'A';
                    667:                BPSHORT(p+1, bit.bid);
                    668:                bit.bid = -1;
                    669:                n = 3;
                    670:        }else if(bit.subfid > 0){
                    671:                /*
                    672:                 * allocate subfont:
                    673:                 *      'K'             1
                    674:                 *      subfont id      2
                    675:                 */
                    676:                if(n<3 || bit.subfid<0)
                    677:                        error(Ebadblt);
                    678:                s = bit.subfont[bit.subfid];
                    679:                if(s==0 || s->ref==0)
                    680:                        error(Ebadfont);
                    681:                p[0] = 'K';
                    682:                BPSHORT(p+1, bit.subfid);
                    683:                bit.subfid = -1;
                    684:                n = 3;
                    685:        }else if(bit.cacheid >= 0){
                    686:                /*
                    687:                 * check cache for subfont:
                    688:                 *      'J'             1
                    689:                 *      subfont id      2
                    690:                 *      font info       3*12
                    691:                 *      fontchars       6*(subfont->n+1)
                    692:                 */
                    693:                p[0] = 'J';
                    694:                if(bit.cacheid < 0)
                    695:                        error(Ebadfont);
                    696:                s = bit.subfont[bit.cacheid];
                    697:                if(s==0 || s->ref==0)
                    698:                        error(Ebadfont);
                    699:                if(n < 3+3*12+6*(s->n+1))
                    700:                        error(Ebadblt);
                    701:                BPSHORT(p+1, bit.cacheid);
                    702:                p += 3;
                    703:                sprint((char*)p, "%11d %11d %11d ", s->n, s->height, s->ascent);
                    704:                p += 3*12;
                    705:                for(i=s->info,j=0; j<=s->n; j++,i++,p+=6){
                    706:                        BPSHORT(p, i->x);
                    707:                        p[2] = i->top;
                    708:                        p[3] = i->bottom;
                    709:                        p[4] = i->left;
                    710:                        p[5] = i->width;
                    711:                }
                    712:                n = 3+3*12+6*(s->n+1);
                    713:                bit.cacheid = -1;
                    714:        }else if(bit.fid >= 0){
                    715:                /*
                    716:                 * allocate font:
                    717:                 *      'N'             1
                    718:                 *      font id         2
                    719:                 */
                    720:                if(n < 3)
                    721:                        error(Ebadblt);
                    722:                if(bit.fid<0 || bit.font[bit.fid]==0)
                    723:                        error(Ebadfont);
                    724:                p[0] = 'N';
                    725:                BPSHORT(p+1, bit.fid);
                    726:                bit.fid = -1;
                    727:                n = 3;
                    728:        }else if(bit.mid >= 0){
                    729:                /*
                    730:                 * read colormap:
                    731:                 *      data            12*(2**bitmapdepth)
                    732:                 */
                    733:                src = bit.map[bit.mid];
                    734:                if(src == 0)
                    735:                        error(Ebadbitmap);
                    736:                l = (1<<src->ldepth);
                    737:                nw = 1 << l;
                    738:                if(n < 12*nw)
                    739:                        error(Ebadblt);
                    740:                for(j = 0; j < nw; j++){
                    741:                        if(bit.mid == 0){
                    742:                                getcolor(flipping? nw-j-1 : j, &rv, &gv, &bv);
                    743:                        }else{
                    744:                                rv = j;
                    745:                                for(off = 32-l; off > 0; off -= l)
                    746:                                        rv = (rv << l) | j;
                    747:                                gv = bv = rv;
                    748:                        }
                    749:                        BPLONG(p, rv);
                    750:                        BPLONG(p+4, gv);
                    751:                        BPLONG(p+8, bv);
                    752:                        p += 12;
                    753:                }
                    754:                bit.mid = -1;
                    755:                n = 12*nw;
                    756:        }else if(bit.rid >= 0){
                    757:                /*
                    758:                 * read bitmap:
                    759:                 *      data            bytewidth*(maxy-miny)
                    760:                 */
                    761:                src = bit.map[bit.rid];
                    762:                if(src == 0)
                    763:                        error(Ebadbitmap);
                    764:                off = 0;
                    765:                if(bit.rid == 0)
                    766:                        off = 1;
                    767:                miny = bit.rminy;
                    768:                maxy = bit.rmaxy;
                    769:                if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
                    770:                        error(Ebadblt);
                    771:                ws = 1<<(3-src->ldepth);        /* pixels per byte */
                    772:                /* set l to number of bytes of incoming data per scan line */
                    773:                if(src->r.min.x >= 0)
                    774:                        l = (src->r.max.x+ws-1)/ws - src->r.min.x/ws;
                    775:                else{   /* make positive before divide */
                    776:                        t = (-src->r.min.x)+ws-1;
                    777:                        t = (t/ws)*ws;
                    778:                        l = (t+src->r.max.x+ws-1)/ws;
                    779:                }
                    780:                if(n < l*(maxy-miny))
                    781:                        error(Ebadblt);
                    782:                if(off)
                    783:                        cursoroff(1);
                    784:                n = 0;
                    785:                p = va;
                    786:                for(y=miny; y<maxy; y++){
                    787:                        q = (uchar*)gaddr(src, Pt(src->r.min.x, y));
                    788:                        q += (src->r.min.x&((sizeof(ulong))*ws-1))/ws;
                    789:                        memmove(p, q, l);
                    790:                        if(islittle)
                    791:                                pixreverse(p, l, src->ldepth);
                    792:                        if(bit.rid==0 && flipping)
                    793:                                /* is screen, so must be word aligned */
                    794:                                for(x=0; x<l; x+=sizeof(ulong),p+=sizeof(ulong))
                    795:                                        *(ulong*)p ^= ~0;
                    796:                        else
                    797:                                p += l;
                    798:                        n += l;
                    799:                }
                    800:                if(off)
                    801:                        cursoron(1);
                    802:                bit.rid = -1;
                    803:        }
                    804: 
                    805:        poperror();
                    806:        qunlock(&bit);
                    807:        return n;
                    808: }
                    809: 
                    810: Point
                    811: bitstrsize(GFont *f, uchar *p, int l)
                    812: {
                    813:        ushort r;
                    814:        Point s = {0,0};
                    815:        GCacheinfo *c;
                    816: 
                    817:        while(l > 0){
                    818:                r = BGSHORT(p);
                    819:                p += 2;
                    820:                l -= 2;
                    821:                if(r >= f->ncache)
                    822:                        continue;
                    823:                c = &f->cache[r];
                    824:                if(c->bottom > s.y)
                    825:                        s.y = c->bottom;
                    826:                s.x += c->width;
                    827:        }
                    828:        return s;
                    829: }
                    830: 
                    831: long
                    832: bitwrite(Chan *c, void *va, long n, ulong offset)
                    833: {
                    834:        uchar *p, *q, *oq;
                    835:        long m, v, miny, maxy, t, x, y;
                    836:        ulong l, nw, ws, rv, q0, q1;
                    837:        ulong *lp;
                    838:        int off, isoff, i, j, ok;
                    839:        ulong *endscreen = gaddr(&gscreen, Pt(0, gscreen.r.max.y));
                    840:        Point pt, pt1, pt2;
                    841:        Rectangle rect;
                    842:        Fcode fc;
                    843:        Fontchar *fcp;
                    844:        GBitmap *src, *dst;
                    845:        BSubfont *f, *tf, **fp;
                    846:        GFont *ff, **ffp;
                    847:        GCacheinfo *gc;
                    848:        char buf[64];
                    849: 
                    850:        if(!conf.monitor)
                    851:                error(Egreg);
                    852:        USED(offset);
                    853: 
                    854:        if(c->qid.path == CHDIR)
                    855:                error(Eisdir);
                    856: 
                    857:        if(c->qid.path == Qmousectl){
                    858:                if(n >= sizeof(buf))
                    859:                        n = sizeof(buf)-1;
                    860:                strncpy(buf, va, n);
                    861:                buf[n] = 0;
                    862:                mousectl(buf);
                    863:                return n;
                    864:        }
                    865: 
                    866:        if(c->qid.path != Qbitblt)
                    867:                error(Egreg);
                    868: 
                    869:        isoff = 0;
                    870:        qlock(&bit);
                    871:        if(waserror()){
                    872:                qunlock(&bit);
                    873:                if(isoff)
                    874:                        cursoron(1);
                    875:                nexterror();
                    876:        }
                    877:        p = va;
                    878:        m = n;
                    879:        SET(src, dst, f, ff);
                    880:        while(m > 0)
                    881:                switch(*p){
                    882:                default:
                    883:                        pprint("bitblt request 0x%x\n", *p);
                    884:                        error(Ebadblt);
                    885: 
                    886:                case 'a':
                    887:                        /*
                    888:                         * allocate:
                    889:                         *      'a'             1
                    890:                         *      ldepth          1
                    891:                         *      Rectangle       16
                    892:                         * next read returns allocated bitmap id
                    893:                         */
                    894:                        if(m < 18)
                    895:                                error(Ebadblt);
                    896:                        v = *(p+1);
                    897:                        if(v > 3)       /* BUG */
                    898:                                error(Ebadblt);
                    899:                        rect.min.x = BGLONG(p+2);
                    900:                        rect.min.y = BGLONG(p+6);
                    901:                        rect.max.x = BGLONG(p+10);
                    902:                        rect.max.y = BGLONG(p+14);
                    903:                        if(Dx(rect) < 0 || Dy(rect) < 0)
                    904:                                error(Ebadblt);
                    905:                        bit.bid = bitalloc(rect, v);
                    906:                        m -= 18;
                    907:                        p += 18;
                    908:                        break;
                    909: 
                    910:                case 'b':
                    911:                        /*
                    912:                         * bitblt
                    913:                         *      'b'             1
                    914:                         *      dst id          2
                    915:                         *      dst Point       8
                    916:                         *      src id          2
                    917:                         *      src Rectangle   16
                    918:                         *      code            2
                    919:                         */
                    920:                        if(m < 31)
                    921:                                error(Ebadblt);
                    922:                        fc = BGSHORT(p+29) & 0xF;
                    923:                        v = BGSHORT(p+11);
                    924:                        if(v<0 || v>=bit.nmap || (src=bit.map[v])==0)
                    925:                                error(Ebadbitmap);
                    926:                        off = 0;
                    927:                        if(v == 0){
                    928:                                if(flipping)
                    929:                                        fc = flipS[fc];
                    930:                                off = 1;
                    931:                        }
                    932:                        v = BGSHORT(p+1);
                    933:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                    934:                                error(Ebadbitmap);
                    935:                        if(v == 0){
                    936:                                if(flipping)
                    937:                                        fc = flipD[fc];
                    938:                                off = 1;
                    939:                        }
                    940:                        pt.x = BGLONG(p+3);
                    941:                        pt.y = BGLONG(p+7);
                    942:                        rect.min.x = BGLONG(p+13);
                    943:                        rect.min.y = BGLONG(p+17);
                    944:                        rect.max.x = BGLONG(p+21);
                    945:                        rect.max.y = BGLONG(p+25);
                    946:                        if(off && !isoff){
                    947:                                cursoroff(1);
                    948:                                isoff = 1;
                    949:                        }
                    950:                        gbitblt(dst, pt, src, rect, fc);
                    951:                        if(dst->base < endscreen)
                    952:                                mbbrect(Rpt(pt, add(pt, sub(rect.max, rect.min))));
                    953:                        m -= 31;
                    954:                        p += 31;
                    955:                        break;
                    956: 
                    957:                case 'c':
                    958:                        /*
                    959:                         * cursorswitch
                    960:                         *      'c'             1
                    961:                         * if nothing more: return to arrow; else
                    962:                         *      Point           8
                    963:                         *      clr             32
                    964:                         *      set             32
                    965:                         */
                    966:                        if(m == 1){
                    967:                                if(!isoff){
                    968:                                        cursoroff(1);
                    969:                                        isoff = 1;
                    970:                                }
                    971:                                Cursortocursor(&arrow);
                    972:                                m -= 1;
                    973:                                p += 1;
                    974:                                break;
                    975:                        }
                    976:                        if(m < 73)
                    977:                                error(Ebadblt);
                    978:                        curs.offset.x = BGLONG(p+1);
                    979:                        curs.offset.y = BGLONG(p+5);
                    980:                        memmove(curs.clr, p+9, 2*16);
                    981:                        memmove(curs.set, p+41, 2*16);
                    982:                        if(islittle){
                    983:                                pixreverse(curs.clr, 2*16, 0);
                    984:                                pixreverse(curs.set, 2*16, 0);
                    985:                        }
                    986:                        if(!isoff){
                    987:                                cursoroff(1);
                    988:                                isoff = 1;
                    989:                        }
                    990:                        Cursortocursor(&curs);
                    991:                        m -= 73;
                    992:                        p += 73;
                    993:                        break;
                    994: 
                    995:                case 'e':
                    996:                        /*
                    997:                         * polysegment
                    998:                         *
                    999:                         *      'e'             1
                   1000:                         *      id              2
                   1001:                         *      pt              8
                   1002:                         *      value           1
                   1003:                         *      code            2
                   1004:                         *      n               2
                   1005:                         *      pts             2*n
                   1006:                         */
                   1007:                        if(m < 16)
                   1008:                                error(Ebadblt);
                   1009:                        l = BGSHORT(p+14);
                   1010:                        if(m < 16+2*l)
                   1011:                                error(Ebadblt);
                   1012:                        v = BGSHORT(p+1);
                   1013:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1014:                                error(Ebadbitmap);
                   1015:                        off = 0;
                   1016:                        fc = BGSHORT(p+12) & 0xF;
                   1017:                        if(v == 0){
                   1018:                                if(flipping)
                   1019:                                        fc = flipD[fc];
                   1020:                                off = 1;
                   1021:                        }
                   1022:                        pt1.x = BGLONG(p+3);
                   1023:                        pt1.y = BGLONG(p+7);
                   1024:                        t = p[11];
                   1025:                        if(off && !isoff){
                   1026:                                cursoroff(1);
                   1027:                                isoff = 1;
                   1028:                        }
                   1029:                        p += 16;
                   1030:                        m -= 16;
                   1031:                        while(l > 0){
                   1032:                                pt2.x = pt1.x + (schar)p[0];
                   1033:                                pt2.y = pt1.y + (schar)p[1];
                   1034:                                gsegment(dst, pt1, pt2, t, fc);
                   1035:                                if(dst->base < endscreen){
                   1036:                                        mbbpt(pt1);
                   1037:                                        mbbpt(pt2);
                   1038:                                }
                   1039:                                pt1 = pt2;
                   1040:                                p += 2;
                   1041:                                m -= 2;
                   1042:                                l--;
                   1043:                        }
                   1044:                        break;
                   1045: 
                   1046:                case 'f':
                   1047:                        /*
                   1048:                         * free
                   1049:                         *      'f'             1
                   1050:                         *      id              2
                   1051:                         */
                   1052:                        if(m < 3)
                   1053:                                error(Ebadblt);
                   1054:                        v = BGSHORT(p+1);
                   1055:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1056:                                error(Ebadbitmap);
                   1057:                        bitfree(dst);
                   1058:                        bit.map[v] = 0;
                   1059:                        m -= 3;
                   1060:                        p += 3;
                   1061:                        break;
                   1062: 
                   1063:                case 'g':
                   1064:                        /*
                   1065:                         * free subfont
                   1066:                         *      'g'             1
                   1067:                         *      id              2
                   1068:                         */
                   1069:                        if(m < 3)
                   1070:                                error(Ebadblt);
                   1071:                        v = BGSHORT(p+1);
                   1072:                        if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0)
                   1073:                                error(Ebadfont);
                   1074:                        subfontfree(f, v);
                   1075:                        m -= 3;
                   1076:                        p += 3;
                   1077:                        break;
                   1078: 
                   1079:                case 'h':
                   1080:                        /*
                   1081:                         * free font
                   1082:                         *      'h'             1
                   1083:                         *      id              2
                   1084:                         */
                   1085:                        if(m < 3)
                   1086:                                error(Ebadblt);
                   1087:                        v = BGSHORT(p+1);
                   1088:                        if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
                   1089:                                error(Ebadfont);
                   1090:                        fontfree(ff);
                   1091:                        bit.font[v] = 0;
                   1092:                        m -= 3;
                   1093:                        p += 3;
                   1094:                        break;
                   1095: 
                   1096:                case 'i':
                   1097:                        /*
                   1098:                         * init
                   1099:                         *
                   1100:                         *      'i'             1
                   1101:                         */
                   1102:                        bit.init = 1;
                   1103:                        m -= 1;
                   1104:                        p += 1;
                   1105:                        break;
                   1106: 
                   1107:                case 'j':
                   1108:                        /*
                   1109:                         * subfont cache check
                   1110:                         *
                   1111:                         *      'j'             1
                   1112:                         *      qid             8
                   1113:                         */
                   1114:                        if(m < 9)
                   1115:                                error(Ebadblt);
                   1116:                        q0 = BGLONG(p+1);
                   1117:                        q1 = BGLONG(p+5);
                   1118:                        i = 0;
                   1119:                        if(q0 != ~0)
                   1120:                                for(; i<bit.nsubfont; i++){
                   1121:                                        f = bit.subfont[i];
                   1122:                                        if(f && f->qid[0]==q0 && f->qid[1]==q1)
                   1123:                                                goto sfcachefound;
                   1124:                                }
                   1125:                        error(Esfnotcached);
                   1126: 
                   1127:                sfcachefound:
                   1128:                        f->ref++;
                   1129:                        bit.cacheid = i;
                   1130:                        m -= 9;
                   1131:                        p += 9;
                   1132:                        break;
                   1133: 
                   1134:                case 'k':
                   1135:                        /*
                   1136:                         * allocate subfont
                   1137:                         *      'k'             1
                   1138:                         *      n               2
                   1139:                         *      height          1
                   1140:                         *      ascent          1
                   1141:                         *      bitmap id       2
                   1142:                         *      qid             8
                   1143:                         *      fontchars       6*(n+1)
                   1144:                         * next read returns allocated font id
                   1145:                         */
                   1146:                        if(m < 15)
                   1147:                                error(Ebadblt);
                   1148:                        v = BGSHORT(p+1);
                   1149:                        if(v<0 || v>NINFO || m<15+6*(v+1))
                   1150:                                error(Ebadblt);
                   1151:                        for(i=1; i<bit.nsubfont; i++)
                   1152:                                if(bit.subfont[i] == 0)
                   1153:                                        goto subfontfound;
                   1154:                        fp = bitmalloc((bit.nsubfont+DMAP)*sizeof(BSubfont*));
                   1155:                        if(fp == 0)
                   1156:                                error(Enomem);
                   1157:                        memmove(fp, bit.subfont, bit.nsubfont*sizeof(BSubfont*));
                   1158:                        free(bit.subfont);
                   1159:                        bit.subfont = fp;
                   1160:                        bit.nsubfont += DMAP;
                   1161:                subfontfound:
                   1162:                        f = bitmalloc(sizeof(BSubfont));
                   1163:                        if(f == 0)
                   1164:                                error(Enomem);
                   1165:                        f->info = bitmalloc((v+1)*sizeof(Fontchar));
                   1166:                        if(f->info == 0){
                   1167:                                free(f);
                   1168:                                error(Enomem);
                   1169:                        }
                   1170:                        bit.subfont[i] = f;
                   1171:                        f->n = v;
                   1172:                        f->height = p[3];
                   1173:                        f->ascent = p[4];
                   1174:                        f->qid[0] = BGLONG(p+7);
                   1175:                        f->qid[1] = BGLONG(p+11);
                   1176:                        /* check to see if already there, uncache if so */
                   1177:                        for(j=0; j<bit.nsubfont; j++){
                   1178:                                if(j == i)
                   1179:                                        continue;
                   1180:                                tf = bit.subfont[j];
                   1181:                                if(tf && tf->qid[0]==f->qid[0] && tf->qid[1]==f->qid[1]){
                   1182:                                        f->qid[0] = ~0; /* uncached */
                   1183:                                        break;
                   1184:                                }
                   1185:                        }
                   1186:                        f->ref = 1;
                   1187:                        v = BGSHORT(p+5);
                   1188:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1189:                                error(Ebadbitmap);
                   1190:                        f->bits = dst;
                   1191:                        bit.map[v] = 0; /* subfont now owns bitmap */
                   1192:                        m -= 15;
                   1193:                        p += 15;
                   1194:                        fcp = f->info;
                   1195:                        for(j=0; j<=f->n; j++,fcp++){
                   1196:                                fcp->x = BGSHORT(p);
                   1197:                                fcp->top = p[2];
                   1198:                                fcp->bottom = p[3];
                   1199:                                fcp->left = p[4];
                   1200:                                fcp->width = p[5];
                   1201:                                fcp->top = p[2];
                   1202:                                p += 6;
                   1203:                                m -= 6;
                   1204:                        }
                   1205:                        bit.subfid = i;
                   1206:                        break;
                   1207: 
                   1208:                case 'l':
                   1209:                        /*
                   1210:                         * line segment
                   1211:                         *
                   1212:                         *      'l'             1
                   1213:                         *      id              2
                   1214:                         *      pt1             8
                   1215:                         *      pt2             8
                   1216:                         *      value           1
                   1217:                         *      code            2
                   1218:                         */
                   1219:                        if(m < 22)
                   1220:                                error(Ebadblt);
                   1221:                        v = BGSHORT(p+1);
                   1222:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1223:                                error(Ebadbitmap);
                   1224:                        off = 0;
                   1225:                        fc = BGSHORT(p+20) & 0xF;
                   1226:                        if(v == 0){
                   1227:                                if(flipping)
                   1228:                                        fc = flipD[fc];
                   1229:                                off = 1;
                   1230:                        }
                   1231:                        pt1.x = BGLONG(p+3);
                   1232:                        pt1.y = BGLONG(p+7);
                   1233:                        pt2.x = BGLONG(p+11);
                   1234:                        pt2.y = BGLONG(p+15);
                   1235:                        t = p[19];
                   1236:                        if(off && !isoff){
                   1237:                                cursoroff(1);
                   1238:                                isoff = 1;
                   1239:                        }
                   1240:                        gsegment(dst, pt1, pt2, t, fc);
                   1241:                        if(dst->base < endscreen){
                   1242:                                mbbpt(pt1);
                   1243:                                mbbpt(pt2);
                   1244:                        }
                   1245:                        m -= 22;
                   1246:                        p += 22;
                   1247:                        break;
                   1248: 
                   1249:                case 'm':
                   1250:                        /*
                   1251:                         * read colormap
                   1252:                         *
                   1253:                         *      'm'             1
                   1254:                         *      id              2
                   1255:                         */
                   1256:                        if(m < 3)
                   1257:                                error(Ebadblt);
                   1258:                        v = BGSHORT(p+1);
                   1259:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1260:                                error(Ebadbitmap);
                   1261:                        bit.mid = v;
                   1262:                        m -= 3;
                   1263:                        p += 3;
                   1264:                        break;
                   1265: 
                   1266:                case 'n':
                   1267:                        /*
                   1268:                         * allocate font
                   1269:                         *      'n'             1
                   1270:                         *      height          1
                   1271:                         *      ascent          1
                   1272:                         *      ldepth          2
                   1273:                         *      ncache          2
                   1274:                         * next read returns allocated font id
                   1275:                         */
                   1276:                        if(m < 7)
                   1277:                                error(Ebadblt);
                   1278:                        v = BGSHORT(p+3);
                   1279:                        t = BGSHORT(p+5);
                   1280:                        if(v<0 || t<0)
                   1281:                                error(Ebadblt);
                   1282:                        for(i=0; i<bit.nfont; i++)
                   1283:                                if(bit.font[i] == 0)
                   1284:                                        goto fontfound;
                   1285:                        ffp = bitmalloc((bit.nfont+DMAP)*sizeof(GFont*));
                   1286:                        if(ffp == 0)
                   1287:                                error(Enomem);
                   1288:                        memmove(ffp, bit.font, bit.nfont*sizeof(GFont*));
                   1289:                        free(bit.font);
                   1290:                        bit.font = ffp;
                   1291:                        bit.nfont += DMAP;
                   1292:                fontfound:
                   1293:                        ff = bitmalloc(sizeof(GFont));
                   1294:                        if(ff == 0)
                   1295:                                error(Enomem);
                   1296:                        ff->ncache = t;
                   1297:                        ff->cache = bitmalloc(t*sizeof(GCacheinfo));
                   1298:                        if(ff->cache == 0){
                   1299:                                free(ff);
                   1300:                                error(Enomem);
                   1301:                        }
                   1302:                        bit.font[i] = ff;
                   1303:                        ff = bit.font[i];
                   1304:                        ff->height = p[1];
                   1305:                        ff->ascent = p[2];
                   1306:                        ff->ldepth = v;
                   1307:                        ff->width = 0;
                   1308:                        ff->b = 0;
                   1309:                        m -= 7;
                   1310:                        p += 7;
                   1311:                        bit.fid = i;
                   1312:                        break;
                   1313: 
                   1314:                case 'p':
                   1315:                        /*
                   1316:                         * point
                   1317:                         *
                   1318:                         *      'p'             1
                   1319:                         *      id              2
                   1320:                         *      pt              8
                   1321:                         *      value           1
                   1322:                         *      code            2
                   1323:                         */
                   1324:                        if(m < 14)
                   1325:                                error(Ebadblt);
                   1326:                        v = BGSHORT(p+1);
                   1327:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1328:                                error(Ebadbitmap);
                   1329:                        off = 0;
                   1330:                        fc = BGSHORT(p+12) & 0xF;
                   1331:                        if(v == 0){
                   1332:                                if(flipping)
                   1333:                                        fc = flipD[fc];
                   1334:                                off = 1;
                   1335:                        }
                   1336:                        pt1.x = BGLONG(p+3);
                   1337:                        pt1.y = BGLONG(p+7);
                   1338:                        t = p[11];
                   1339:                        if(off && !isoff){
                   1340:                                cursoroff(1);
                   1341:                                isoff = 1;
                   1342:                        }
                   1343:                        gpoint(dst, pt1, t, fc);
                   1344:                        if(dst->base < endscreen)
                   1345:                                mbbpt(pt1);
                   1346:                        m -= 14;
                   1347:                        p += 14;
                   1348:                        break;
                   1349: 
                   1350:                case 'q':
                   1351:                        /*
                   1352:                         * clip rectangle
                   1353:                         *      'q'             1
                   1354:                         *      id              2
                   1355:                         *      rect            16
                   1356:                         */
                   1357:                        if(m < 19)
                   1358:                                error(Ebadblt);
                   1359:                        v = BGSHORT(p+1);
                   1360:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1361:                                error(Ebadbitmap);
                   1362:                        rect.min.x = BGLONG(p+3);
                   1363:                        rect.min.y = BGLONG(p+7);
                   1364:                        rect.max.x = BGLONG(p+11);
                   1365:                        rect.max.y = BGLONG(p+15);
                   1366:                        if(rectclip(&rect, dst->r))
                   1367:                                dst->clipr = rect;
                   1368:                        m -= 19;
                   1369:                        p += 19;
                   1370:                        break;
                   1371: 
                   1372:                case 'r':
                   1373:                        /*
                   1374:                         * read
                   1375:                         *      'r'             1
                   1376:                         *      src id          2
                   1377:                         *      miny            4
                   1378:                         *      maxy            4
                   1379:                         */
                   1380:                        if(m < 11)
                   1381:                                error(Ebadblt);
                   1382:                        v = BGSHORT(p+1);
                   1383:                        if(v<0 || v>=bit.nmap || (src=bit.map[v])==0)
                   1384:                                error(Ebadbitmap);
                   1385:                        miny = BGLONG(p+3);
                   1386:                        maxy = BGLONG(p+7);
                   1387:                        if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
                   1388:                                error(Ebadblt);
                   1389:                        bit.rid = v;
                   1390:                        bit.rminy = miny;
                   1391:                        bit.rmaxy = maxy;
                   1392:                        p += 11;
                   1393:                        m -= 11;
                   1394:                        break;
                   1395: 
                   1396:                case 's':
                   1397:                        /*
                   1398:                         * string
                   1399:                         *      's'             1
                   1400:                         *      id              2
                   1401:                         *      pt              8
                   1402:                         *      font id         2
                   1403:                         *      code            2
                   1404:                         *      n               2
                   1405:                         *      cache indices   2*n (not null terminated)
                   1406:                         */
                   1407:                        if(m < 17)
                   1408:                                error(Ebadblt);
                   1409:                        v = BGSHORT(p+1);
                   1410:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1411:                                error(Ebadbitmap);
                   1412:                        off = 0;
                   1413:                        fc = BGSHORT(p+13) & 0xF;
                   1414:                        if(v == 0){
                   1415:                                if(flipping)
                   1416:                                        fc = flipD[fc];
                   1417:                                off = 1;
                   1418:                        }
                   1419:                        pt.x = BGLONG(p+3);
                   1420:                        pt.y = BGLONG(p+7);
                   1421:                        v = BGSHORT(p+11);
                   1422:                        if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
                   1423:                                error(Ebadfont);
                   1424:                        l = BGSHORT(p+15)*2;
                   1425:                        p += 17;
                   1426:                        m -= 17;
                   1427:                        if(l > m)
                   1428:                                error(Ebadblt);
                   1429:                        if(off && !isoff){
                   1430:                                cursoroff(1);
                   1431:                                isoff = 1;
                   1432:                        }
                   1433:                        bitstring(dst, pt, ff, p, l, fc);
                   1434:                        if(dst->base < endscreen)
                   1435:                                mbbrect(Rpt(pt, add(pt, bitstrsize(ff, p, l))));
                   1436:                        m -= l;
                   1437:                        p += l;
                   1438:                        break;
                   1439: 
                   1440:                case 't':
                   1441:                        /*
                   1442:                         * texture
                   1443:                         *      't'             1
                   1444:                         *      dst id          2
                   1445:                         *      rect            16
                   1446:                         *      src id          2
                   1447:                         *      fcode           2
                   1448:                         */
                   1449:                        if(m < 23)
                   1450:                                error(Ebadblt);
                   1451:                        v = BGSHORT(p+1);
                   1452:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1453:                                error(Ebadbitmap);
                   1454:                        off = 0;
                   1455:                        fc = BGSHORT(p+21) & 0xF;
                   1456:                        if(v == 0){
                   1457:                                if(flipping)
                   1458:                                        fc = flipD[fc];
                   1459:                                off = 1;
                   1460:                        }
                   1461:                        rect.min.x = BGLONG(p+3);
                   1462:                        rect.min.y = BGLONG(p+7);
                   1463:                        rect.max.x = BGLONG(p+11);
                   1464:                        rect.max.y = BGLONG(p+15);
                   1465:                        v = BGSHORT(p+19);
                   1466:                        if(v<0 || v>=bit.nmap || (src=bit.map[v])==0)
                   1467:                                error(Ebadbitmap);
                   1468:                        if(off && !isoff){
                   1469:                                cursoroff(1);
                   1470:                                isoff = 1;
                   1471:                        }
                   1472:                        gtexture(dst, rect, src, fc);
                   1473:                        if(dst->base < endscreen)
                   1474:                                mbbrect(rect);
                   1475:                        m -= 23;
                   1476:                        p += 23;
                   1477:                        break;
                   1478: 
                   1479:                case 'v':
                   1480:                        /*
                   1481:                         * clear font cache and bitmap.
                   1482:                         * if error, font is unchanged.
                   1483:                         *      'v'             1
                   1484:                         *      id              2
                   1485:                         *      ncache          2
                   1486:                         *      width           2
                   1487:                         */
                   1488:                        if(m < 7)
                   1489:                                error(Ebadblt);
                   1490:                        v = BGSHORT(p+1);
                   1491:                        t = BGSHORT(p+3);
                   1492:                        if(t<0 || v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
                   1493:                                error(Ebadblt);
                   1494:                        x = BGSHORT(p+5);
                   1495:                        i = bitalloc(Rect(0, 0, t*x, ff->height), ff->ldepth);
                   1496:                        if(t != ff->ncache){
                   1497:                                gc = bitmalloc(t*sizeof(ff->cache[0]));
                   1498:                                if(gc == 0){
                   1499:                                        bitfree(bit.map[i]);
                   1500:                                        bit.map[i] = 0;
                   1501:                                        error(Enomem);
                   1502:                                }
                   1503:                                free(ff->cache);
                   1504:                                ff->cache = gc;
                   1505:                                ff->ncache = t;
                   1506:                        }else{
                   1507:                                /*
                   1508:                                 * memset not necessary but helps avoid
                   1509:                                 * confusion if the cache is mishandled by the
                   1510:                                 * user.
                   1511:                                 */
                   1512:                                memset(ff->cache, 0, t*sizeof(ff->cache[0]));
                   1513:                        }
                   1514:                        if(ff->b)
                   1515:                                bitfree(ff->b);
                   1516:                        ff->b = bit.map[i];
                   1517:                        bit.map[i] = 0; /* disconnect it from GBitmap space */
                   1518:                        ff->width = x;
                   1519:                        p += 7;
                   1520:                        m -= 7;
                   1521:                        break;
                   1522: 
                   1523:                case 'w':
                   1524:                        /*
                   1525:                         * write
                   1526:                         *      'w'             1
                   1527:                         *      dst id          2
                   1528:                         *      miny            4
                   1529:                         *      maxy            4
                   1530:                         *      data            bytewidth*(maxy-miny)
                   1531:                         */
                   1532:                        if(m < 11)
                   1533:                                error(Ebadblt);
                   1534:                        v = BGSHORT(p+1);
                   1535:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
                   1536:                                error(Ebadbitmap);
                   1537:                        off = 0;
                   1538:                        if(v == 0)
                   1539:                                off = 1;
                   1540:                        miny = BGLONG(p+3);
                   1541:                        maxy = BGLONG(p+7);
                   1542:                        if(miny>maxy || miny<dst->r.min.y || maxy>dst->r.max.y)
                   1543:                                error(Ebadblt);
                   1544:                        ws = 1<<(3-dst->ldepth);        /* pixels per byte */
                   1545:                        /* set l to number of bytes of incoming data per scan line */
                   1546:                        if(dst->r.min.x >= 0)
                   1547:                                l = (dst->r.max.x+ws-1)/ws - dst->r.min.x/ws;
                   1548:                        else{   /* make positive before divide */
                   1549:                                t = (-dst->r.min.x)+ws-1;
                   1550:                                t = (t/ws)*ws;
                   1551:                                l = (t+dst->r.max.x+ws-1)/ws;
                   1552:                        }
                   1553:                        if(dst->base < endscreen)
                   1554:                                mbbrect(Rect(dst->r.min.x, miny, dst->r.max.x, maxy));
                   1555:                        p += 11;
                   1556:                        m -= 11;
                   1557:                        if(m < l*(maxy-miny))
                   1558:                                error(Ebadblt);
                   1559:                        if(off && !isoff){
                   1560:                                cursoroff(1);
                   1561:                                isoff = 1;
                   1562:                        }
                   1563:                        for(y=miny; y<maxy; y++){
                   1564:                                oq = (uchar*)gaddr(dst, Pt(dst->r.min.x, y));
                   1565:                                q = oq + (dst->r.min.x&((sizeof(ulong))*ws-1))/ws;
                   1566:                                memmove(q, p, l);
                   1567:                                if(islittle)
                   1568:                                        pixreverse(q, l, dst->ldepth);
                   1569:                                if(v==0 && flipping){   /* flip bits */
                   1570:                                        /* we know it's all word aligned */
                   1571:                                        lp = (ulong*)oq;
                   1572:                                        for(x=0; x<l; x+=sizeof(ulong))
                   1573:                                                *lp++ ^= ~0;
                   1574:                                }
                   1575:                                p += l;
                   1576:                                m -= l;
                   1577:                        }
                   1578:                        if(v == 0)
                   1579:                                hwscreenwrite(miny, maxy);
                   1580:                        break;
                   1581: 
                   1582:                case 'x':
                   1583:                        /*
                   1584:                         * cursorset
                   1585:                         *
                   1586:                         *      'x'             1
                   1587:                         *      pt              8
                   1588:                         */
                   1589:                        if(m < 9)
                   1590:                                error(Ebadblt);
                   1591:                        pt1.x = BGLONG(p+1);
                   1592:                        pt1.y = BGLONG(p+5);
                   1593:                        if(ptinrect(pt1, gscreen.r)){
                   1594:                                mouse.xy = pt1;
                   1595:                                mouse.redraw = 1;
                   1596:                                mouse.track = 1;
                   1597:                                mouseclock();
                   1598:                        }
                   1599:                        m -= 9;
                   1600:                        p += 9;
                   1601:                        break;
                   1602: 
                   1603:                case 'y':
                   1604:                        /*
                   1605:                         * load font from subfont
                   1606:                         *      'y'             1
                   1607:                         *      id              2
                   1608:                         *      cache index     2
                   1609:                         *      subfont id      2
                   1610:                         *      subfont index   2
                   1611:                         */
                   1612:                        if(m < 9)
                   1613:                                error(Ebadblt);
                   1614:                        v = BGSHORT(p+1);
                   1615:                        if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
                   1616:                                error(Ebadblt);
                   1617:                        if(ff->b == 0)
                   1618:                                error(Ebadbitmap);
                   1619:                        l = BGSHORT(p+3);
                   1620:                        if(l >= ff->ncache)
                   1621:                                error(Ebadblt);
                   1622:                        v = BGSHORT(p+5);
                   1623:                        if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0)
                   1624:                                error(Ebadfont);
                   1625:                        nw = BGSHORT(p+7);
                   1626:                        if(nw >= f->n)
                   1627:                                error(Ebadblt);
                   1628:                        bitloadchar(ff, l, f, nw);
                   1629:                        p += 9;
                   1630:                        m -= 9;
                   1631:                        break;
                   1632: 
                   1633:                case 'z':
                   1634:                        /*
                   1635:                         * write the colormap
                   1636:                         *
                   1637:                         *      'z'             1
                   1638:                         *      id              2
                   1639:                         *      map             12*(2**bitmapdepth)
                   1640:                         */
                   1641:                        if(m < 3)
                   1642:                                error(Ebadblt);
                   1643:                        v = BGSHORT(p+1);
                   1644:                        if(v != 0)
                   1645:                                error(Ebadbitmap);
                   1646:                        m -= 3;
                   1647:                        p += 3;
                   1648:                        nw = 1 << (1 << gscreen.ldepth);
                   1649:                        if(m < 12*nw)
                   1650:                                error(Ebadblt);
                   1651:                        ok = 1;
                   1652:                        for(i = 0; i < nw; i++){
                   1653:                                ok &= setcolor(flipping ? ~i : i, BGLONG(p), BGLONG(p+4), BGLONG(p+8));
                   1654:                                p += 12;
                   1655:                                m -= 12;
                   1656:                        }
                   1657:                        if(!ok){
                   1658:                                /* assume monochrome: possibly change flipping */
                   1659:                                l = BGLONG(p-12);
                   1660:                                getcolor(nw-1, &rv, &rv, &rv);
                   1661:                                flipping = (l != rv);
                   1662:                        }
                   1663:                        break;
                   1664:                }
                   1665: 
                   1666:        poperror();
                   1667:        if(isoff)
                   1668:                cursoron(1);
                   1669:        screenupdate();
                   1670:        qunlock(&bit);
                   1671:        return n;
                   1672: }
                   1673: 
                   1674: int
                   1675: bitalloc(Rectangle rect, int ld)
                   1676: {
                   1677:        Arena *a, *ea, *aa;
                   1678:        GBitmap *b, **bp, **ep;
                   1679:        ulong l, ws, nw;
                   1680:        long t;
                   1681: 
                   1682:        ws = BI2WD>>ld; /* pixels per word */
                   1683:        if(rect.min.x >= 0){
                   1684:                l = (rect.max.x+ws-1)/ws;
                   1685:                l -= rect.min.x/ws;
                   1686:        }else{  /* make positive before divide */
                   1687:                t = (-rect.min.x)+ws-1;
                   1688:                t = (t/ws)*ws;
                   1689:                l = (t+rect.max.x+ws-1)/ws;
                   1690:        }
                   1691:        nw = l*Dy(rect);
                   1692:        ea = &bit.arena[bit.narena];
                   1693: 
                   1694:        /* first try easy fit */
                   1695:        for(a=bit.arena; a<ea; a++){
                   1696:                if(a->words == 0)
                   1697:                        continue;
                   1698:                if(a->wfree+HDR+nw <= a->words+a->nwords)
                   1699:                        goto found;
                   1700:        }
                   1701: 
                   1702:        /* compact and try again */
                   1703:        bitcompact();
                   1704:        aa = 0;
                   1705:        for(a=bit.arena; a<ea; a++){
                   1706:                if(a->words == 0){
                   1707:                        if(aa == 0)
                   1708:                                aa = a;
                   1709:                        continue;
                   1710:                }
                   1711:                if(a->wfree+HDR+nw <= a->words+a->nwords)
                   1712:                        goto found;
                   1713:        }
                   1714: 
                   1715:        /* need new arena */
                   1716:        if(aa){
                   1717:                a = aa;
                   1718:                a->nwords = HDR + (gscreen.r.max.y*gscreen.r.max.x)/ws;
                   1719:                if(a->nwords < HDR+nw)
                   1720:                        a->nwords = HDR+nw;
                   1721:                a->words = xalloc(a->nwords*sizeof(ulong));
                   1722:                if(a->words){
                   1723:                        a->wfree = a->words;
                   1724:                        a->nbusy = 0;
                   1725:                        goto found;
                   1726:                }
                   1727:        }
                   1728:        /* else can't grow list: bitmaps have backpointers */
                   1729: 
                   1730:        bitfreeup();
                   1731: 
                   1732:        for(a=bit.arena; a<ea; a++){
                   1733:                if(a->words == 0)
                   1734:                        continue;
                   1735:                if(a->wfree+HDR+nw <= a->words+a->nwords)
                   1736:                        goto found;
                   1737:        }
                   1738:        if(a == ea)
                   1739:                error(Enobitstore);
                   1740:        
                   1741:     found:
                   1742:        b = bitmalloc(sizeof(GBitmap));
                   1743:        if(b == 0)
                   1744:                error(Enomem);
                   1745:        *a->wfree++ = nw;
                   1746:        *a->wfree++ = (ulong)a;
                   1747:        *a->wfree++ = (ulong)b;
                   1748:        memset(a->wfree, 0, nw*sizeof(ulong));
                   1749:        b->base = a->wfree;
                   1750:        a->wfree += nw;
                   1751:        a->nbusy++;
                   1752:        b->zero = l*rect.min.y;
                   1753:        if(rect.min.x >= 0)
                   1754:                b->zero += rect.min.x/ws;
                   1755:        else
                   1756:                b->zero -= (-rect.min.x+ws-1)/ws;
                   1757:        b->zero = -b->zero;
                   1758:        b->width = l;
                   1759:        b->ldepth = ld;
                   1760:        b->r = rect;
                   1761:        b->clipr = rect;
                   1762:        b->cache = 0;
                   1763:        /* worth doing better than linear lookup? */
                   1764:        ep = bit.map+bit.nmap;
                   1765:        for(bp=bit.map; bp<ep; bp++)
                   1766:                if(*bp == 0)
                   1767:                        break;
                   1768:        if(bp == ep){
                   1769:                bp = bitmalloc((bit.nmap+DMAP)*sizeof(GBitmap*));
                   1770:                if(bp == 0){
                   1771:                        bitfree(b);
                   1772:                        error(Enomem);
                   1773:                }
                   1774:                memmove(bp, bit.map, bit.nmap*sizeof(GBitmap*));
                   1775:                free(bit.map);
                   1776:                bit.map = bp;
                   1777:                bp += bit.nmap;
                   1778:                bit.nmap += DMAP;
                   1779:        }
                   1780:        *bp = b;
                   1781:        return bp-bit.map;
                   1782: }
                   1783: 
                   1784: void
                   1785: bitfree(GBitmap *b)
                   1786: {
                   1787:        Arena *a;
                   1788: 
                   1789:        if(b->base != gscreen.base){    /* can't free screen memory */
                   1790:                a = (Arena*)(b->base[-2]);
                   1791:                a->nbusy--;
                   1792:                if(a->nbusy == 0)
                   1793:                        arenafree(a);
                   1794:                b->base[-1] = 0;
                   1795:        }
                   1796:        free(b);
                   1797: }
                   1798: 
                   1799: void
                   1800: fontfree(GFont *f)
                   1801: {
                   1802:        if(f->b)
                   1803:                bitfree(f->b);
                   1804:        free(f->cache);
                   1805:        free(f);
                   1806: }
                   1807: 
                   1808: void
                   1809: subfontfree(BSubfont *s, int i)
                   1810: {
                   1811:        if(s!=bdefont && s->ref>0){     /* don't free subfont 0, bdefont */
                   1812:                s->ref--;
                   1813:                if(s->ref==0 && s->qid[0]==~0){ /* uncached */
                   1814:                        bitfree(s->bits);
                   1815:                        free(s->info);
                   1816:                        free(s);
                   1817:                        bit.subfont[i] = 0;
                   1818:                }
                   1819:        }
                   1820:        return;
                   1821: }
                   1822: 
                   1823: void
                   1824: arenafree(Arena *a)
                   1825: {
                   1826:        xfree(a->words);
                   1827:        a->words = 0;
                   1828: }
                   1829: 
                   1830: void
                   1831: bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc)
                   1832: {
                   1833:        int full;
                   1834:        Rectangle rect;
                   1835:        ushort r;
                   1836:        GCacheinfo *c;
                   1837:        int x;
                   1838:        Fcode clr;
                   1839: 
                   1840:        clr = 0;
                   1841:        full = (fc&~S)^(D&~S);  /* result involves source */
                   1842:        if(full){
                   1843:                rect.min.y = 0;
                   1844:                rect.max.y = f->height;
                   1845:                /* set clr to result under fc if source pixel is zero */
                   1846:                /* hard to do without knowing layout of bits, so we cheat */
                   1847:                clr = (fc&3);   /* fc&3 is result if source is zero */
                   1848:                clr |= clr<<2;  /* fc&(3<<2) is result if source is one */
                   1849:        }
                   1850: 
                   1851:        while(l > 0){
                   1852:                r = BGSHORT(p);
                   1853:                p += 2;
                   1854:                l -= 2;
                   1855:                if(r >= f->ncache)
                   1856:                        continue;
                   1857:                c = &f->cache[r];
                   1858:                if(!full){
                   1859:                        rect.min.y = c->top;
                   1860:                        rect.max.y = c->bottom;
                   1861:                }else{
                   1862:                        if(c->left > 0)
                   1863:                                gbitblt(bp, pt, bp,
                   1864:                                        Rect(pt.x, pt.y, pt.x+c->left, pt.y+f->height),
                   1865:                                        clr);
                   1866:                        x = c->left+(c->xright-c->x);
                   1867:                        if(x < c->width)
                   1868:                                gbitblt(bp, Pt(pt.x+x, pt.y), bp,
                   1869:                                        Rect(pt.x+x, pt.y, pt.x+c->width, pt.y+f->height),
                   1870:                                        clr);
                   1871:                }
                   1872:                rect.min.x = c->x;
                   1873:                rect.max.x = c->xright;
                   1874:                gbitblt(bp, Pt(pt.x+c->left, pt.y+rect.min.y), f->b, rect, fc);
                   1875:                pt.x += c->width;
                   1876:        }
                   1877: }
                   1878: 
                   1879: void
                   1880: bitloadchar(GFont *f, int ci, GSubfont *subf, int si)
                   1881: {
                   1882:        GCacheinfo *c;
                   1883:        Rectangle rect;
                   1884:        Fontchar *fi;
                   1885:        int y;
                   1886: 
                   1887:        c = &f->cache[ci];
                   1888:        fi = &subf->info[si];
                   1889:        /* careful about sign extension: top and bottom are uchars */
                   1890:        y = fi->top + (f->ascent-subf->ascent);
                   1891:        if(y < 0)
                   1892:                y = 0;
                   1893:        c->top = y;
                   1894:        y = fi->bottom + (f->ascent-subf->ascent);
                   1895:        if(y < 0)
                   1896:                y = 0;
                   1897:        c->bottom = y;
                   1898:        c->width = fi->width;
                   1899:        c->left = fi->left;
                   1900:        c->x = ci*f->width;
                   1901:        c->xright = c->x + ((fi+1)->x - fi->x);
                   1902:        rect.min.y = 0;
                   1903:        rect.max.y = f->height;
                   1904:        rect.min.x = c->x;
                   1905:        rect.max.x = c->x+f->width;
                   1906:        gbitblt(f->b, rect.min, f->b, rect, 0);
                   1907:        rect.min.x = fi->x;
                   1908:        rect.max.x = (fi+1)->x;
                   1909:        rect.max.y = subf->height;
                   1910:        gbitblt(f->b, Pt(c->x, f->ascent-subf->ascent), subf->bits, rect, S);
                   1911: }
                   1912: 
                   1913: QLock  bitlock;
                   1914: 
                   1915: GBitmap*
                   1916: id2bit(int v)
                   1917: {
                   1918:        GBitmap *bp=0;
                   1919: 
                   1920:        if(v<0 || v>=bit.nmap || (bp=bit.map[v])==0)
                   1921:                error(Ebadbitmap);
                   1922:        return bp;
                   1923: }
                   1924: 
                   1925: void
                   1926: bitcompact(void)
                   1927: {
                   1928:        Arena *a, *ea, *na;
                   1929:        ulong *p1, *p2, n;
                   1930: 
                   1931:        qlock(&bitlock);
                   1932:        ea = &bit.arena[bit.narena];
                   1933:        for(a=bit.arena; a<ea; a++){
                   1934:                if(a->words == 0)
                   1935:                        continue;
                   1936:                /* first compact what's here */
                   1937:                p1 = p2 = a->words;
                   1938:                while(p2 < a->wfree){
                   1939:                        n = HDR+p2[0];
                   1940:                        if(p2[2] == 0){
                   1941:                                p2 += n;
                   1942:                                continue;
                   1943:                        }
                   1944:                        if(p1 != p2){
                   1945:                                memmove(p1, p2, n*sizeof(ulong));
                   1946:                                ((GBitmap*)p1[2])->base = p1+HDR;
                   1947:                        }
                   1948:                        p2 += n;
                   1949:                        p1 += n;
                   1950:                }
                   1951:                /* now pull stuff from later arena to fill this one */
                   1952:                na = a+1;
                   1953:                while(na<ea && p1<a->words+a->nwords){
                   1954:                        p2 = na->words;
                   1955:                        if(p2 == 0){
                   1956:                                na++;
                   1957:                                continue;
                   1958:                        }
                   1959:                        while(p2 < na->wfree){
                   1960:                                n = HDR+p2[0];
                   1961:                                if(p2[2] == 0){
                   1962:                                        p2 += n;
                   1963:                                        continue;
                   1964:                                }
                   1965:                                if(p1+n < a->words+a->nwords){
                   1966:                                        memmove(p1, p2, n*sizeof(ulong));
                   1967:                                        ((GBitmap*)p1[2])->base = p1+HDR;
                   1968:                                        /* block now in new arena... */
                   1969:                                        p1[1] = (ulong)a;
                   1970:                                        a->nbusy++;
                   1971:                                        /* ... not in old arena */
                   1972:                                        na->nbusy--;
                   1973:                                        p2[2] = 0;
                   1974:                                        p1 += n;
                   1975:                                }
                   1976:                                p2 += n;
                   1977:                        }
                   1978:                        na++;
                   1979:                }
                   1980:                a->wfree = p1;
                   1981:        }
                   1982:        for(a=bit.arena; a<ea; a++)
                   1983:                if(a->words && a->nbusy==0)
                   1984:                        arenafree(a);
                   1985:        qunlock(&bitlock);
                   1986: }
                   1987: 
                   1988: void
                   1989: Cursortocursor(Cursor *c)
                   1990: {
                   1991:        lock(&cursor);
                   1992:        memmove(&cursor, c, sizeof(Cursor));
                   1993:        setcursor(c);
                   1994:        unlock(&cursor);
                   1995: }
                   1996: 
                   1997: int
                   1998: cursoron(int dolock)
                   1999: {
                   2000:        int ret;
                   2001: 
                   2002:        if(dolock)
                   2003:                lock(&cursor);
                   2004:        ret = 0;
                   2005:        if(hwcurs)
                   2006:                ret = hwgcmove(mouse.xy);
                   2007:        else if(cursor.visible++ == 0){
                   2008:                cursor.r.min = mouse.xy;
                   2009:                cursor.r.max = add(mouse.xy, Pt(16, 16));
                   2010:                cursor.r = raddp(cursor.r, cursor.offset);
                   2011:                gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S);
                   2012:                gbitblt(&gscreen, cursor.r.min,
                   2013:                        &clr, Rect(0, 0, 16, 16), flipping? flipD[D&~S] : D&~S);
                   2014:                gbitblt(&gscreen, cursor.r.min,
                   2015:                        &set, Rect(0, 0, 16, 16), flipping? flipD[S|D] : S|D);
                   2016:                mbbrect(cursor.r);
                   2017:        }
                   2018:        if(dolock)
                   2019:                unlock(&cursor);
                   2020: 
                   2021:        return ret;
                   2022: }
                   2023: 
                   2024: void
                   2025: cursoroff(int dolock)
                   2026: {
                   2027:        if(hwcurs)
                   2028:                return;
                   2029:        if(dolock)
                   2030:                lock(&cursor);
                   2031:        if(--cursor.visible == 0) {
                   2032:                gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S);
                   2033:                mbbrect(cursor.r);
                   2034:                mousescreenupdate();
                   2035:        }
                   2036:        if(dolock)
                   2037:                unlock(&cursor);
                   2038: }
                   2039: 
                   2040: /*
                   2041:  *  called by the clock routine to redraw the cursor
                   2042:  */
                   2043: void
                   2044: mouseclock(void)
                   2045: {
                   2046:        if(mouse.track){
                   2047:                mousetrack(mouse.buttons, mouse.dx, mouse.dy);
                   2048:                mouse.track = 0;
                   2049:                mouse.dx = 0;
                   2050:                mouse.dy = 0;
                   2051:        }
                   2052:        if(mouse.redraw && canlock(&cursor)){
                   2053:                mouse.redraw = 0;
                   2054:                cursoroff(0);
                   2055:                mouse.redraw = cursoron(0);
                   2056:                mousescreenupdate();
                   2057:                unlock(&cursor);
                   2058:        }
                   2059: }
                   2060: 
                   2061: /*
                   2062:  *  called at interrupt level to update the structure and
                   2063:  *  awaken any waiting procs.
                   2064:  */
                   2065: void
                   2066: mousetrack(int b, int dx, int dy)
                   2067: {
                   2068:        int x, y;
                   2069: 
                   2070:        x = mouse.xy.x + dx;
                   2071:        if(x < gscreen.r.min.x)
                   2072:                x = gscreen.r.min.x;
                   2073:        if(x >= gscreen.r.max.x)
                   2074:                x = gscreen.r.max.x;
                   2075:        y = mouse.xy.y + dy;
                   2076:        if(y < gscreen.r.min.y)
                   2077:                y = gscreen.r.min.y;
                   2078:        if(y >= gscreen.r.max.y)
                   2079:                y = gscreen.r.max.y;
                   2080:        mouse.counter++;
                   2081:        mouse.xy = Pt(x, y);
                   2082:        mouse.buttons = b;
                   2083:        mouse.redraw = 1;
                   2084:        wakeup(&mouse.r);
                   2085: }
                   2086: 
                   2087: /*
                   2088:  *  microsoft 3 button, 7 bit bytes
                   2089:  *
                   2090:  *     byte 0 -        1  L  R Y7 Y6 X7 X6
                   2091:  *     byte 1 -        0 X5 X4 X3 X2 X1 X0
                   2092:  *     byte 2 -        0 Y5 Y4 Y3 Y2 Y1 Y0
                   2093:  *     byte 3 -        0  M  x  x  x  x  x     (optional)
                   2094:  *
                   2095:  *  shift & right button is the same as middle button (for 2 button mice)
                   2096:  */
                   2097: int
                   2098: m3mouseputc(IOQ *q, int c)
                   2099: {
                   2100:        static uchar msg[3];
                   2101:        static int nb;
                   2102:        static int middle;
                   2103:        static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 5 };
                   2104:        short x;
                   2105:        int dx, dy, newbuttons;
                   2106: 
                   2107:        USED(q);
                   2108:        /* 
                   2109:         *  check bit 6 for consistency
                   2110:         */
                   2111:        if(nb==0){
                   2112:                if((c&0x40) == 0){
                   2113:                        /* an extra byte gets sent for the middle button */
                   2114:                        middle = (c&0x20) ? 2 : 0;
                   2115:                        newbuttons = (mouse.buttons & ~2) | middle;
                   2116:                        mousetrack(newbuttons, 0, 0);
                   2117:                        return 0;
                   2118:                }
                   2119:        }
                   2120:        msg[nb] = c;
                   2121:        if(++nb == 3){
                   2122:                nb = 0;
                   2123:                newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)];
                   2124:                x = (msg[0]&0x3)<<14;
                   2125:                dx = (x>>8) | msg[1];
                   2126:                x = (msg[0]&0xc)<<12;
                   2127:                dy = (x>>8) | msg[2];
                   2128:                mousetrack(newbuttons, dx, dy);
                   2129:        }
                   2130:        return 0;
                   2131: }
                   2132: 
                   2133: /*
                   2134:  *  Logitech 5 byte packed binary mouse format, 8 bit bytes
                   2135:  *
                   2136:  *  shift & right button is the same as middle button (for 2 button mice)
                   2137:  */
                   2138: int
                   2139: mouseputc(IOQ *q, int c)
                   2140: {
                   2141:        static short msg[5];
                   2142:        static int nb;
                   2143:        static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 5, 3, 7};
                   2144:        int dx, dy, newbuttons;
                   2145: 
                   2146:        USED(q);
                   2147:        if((c&0xF0) == 0x80)
                   2148:                nb=0;
                   2149:        msg[nb] = c;
                   2150:        if(c & 0x80)
                   2151:                msg[nb] |= ~0xFF;       /* sign extend */
                   2152:        if(++nb == 5){
                   2153:                newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)];
                   2154:                dx = msg[1]+msg[3];
                   2155:                dy = -(msg[2]+msg[4]);
                   2156:                mousetrack(newbuttons, dx, dy);
                   2157:                nb = 0;
                   2158:        }
                   2159:        return 0;
                   2160: }
                   2161: 
                   2162: int
                   2163: mousechanged(void *m)
                   2164: {
                   2165:        USED(m);
                   2166:        return mouse.lastcounter != mouse.counter;
                   2167: }
                   2168: 
                   2169: /*
                   2170:  *  reverse pixels into little endian order
                   2171:  */
                   2172: uchar revtab0[] = {
                   2173:  0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
                   2174:  0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
                   2175:  0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
                   2176:  0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
                   2177:  0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
                   2178:  0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
                   2179:  0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
                   2180:  0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
                   2181:  0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
                   2182:  0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
                   2183:  0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
                   2184:  0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
                   2185:  0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
                   2186:  0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
                   2187:  0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
                   2188:  0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
                   2189:  0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
                   2190:  0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
                   2191:  0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
                   2192:  0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
                   2193:  0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
                   2194:  0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
                   2195:  0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
                   2196:  0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
                   2197:  0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
                   2198:  0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
                   2199:  0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
                   2200:  0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
                   2201:  0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
                   2202:  0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
                   2203:  0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
                   2204:  0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
                   2205: };
                   2206: uchar revtab1[] = {
                   2207:  0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0,
                   2208:  0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0,
                   2209:  0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4,
                   2210:  0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4,
                   2211:  0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8,
                   2212:  0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8,
                   2213:  0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc,
                   2214:  0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc,
                   2215:  0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1,
                   2216:  0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1,
                   2217:  0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5,
                   2218:  0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5,
                   2219:  0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9,
                   2220:  0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9,
                   2221:  0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd,
                   2222:  0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd,
                   2223:  0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2,
                   2224:  0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2,
                   2225:  0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6,
                   2226:  0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6,
                   2227:  0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda,
                   2228:  0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa,
                   2229:  0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde,
                   2230:  0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe,
                   2231:  0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3,
                   2232:  0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3,
                   2233:  0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7,
                   2234:  0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7,
                   2235:  0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb,
                   2236:  0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb,
                   2237:  0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf,
                   2238:  0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff,
                   2239: };
                   2240: uchar revtab2[] = {
                   2241:  0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
                   2242:  0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
                   2243:  0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
                   2244:  0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1,
                   2245:  0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
                   2246:  0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2, 0xe2, 0xf2,
                   2247:  0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
                   2248:  0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3,
                   2249:  0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
                   2250:  0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4,
                   2251:  0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
                   2252:  0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5,
                   2253:  0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
                   2254:  0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6,
                   2255:  0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
                   2256:  0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7,
                   2257:  0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
                   2258:  0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8,
                   2259:  0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
                   2260:  0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9,
                   2261:  0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a,
                   2262:  0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
                   2263:  0x0b, 0x1b, 0x2b, 0x3b, 0x4b, 0x5b, 0x6b, 0x7b,
                   2264:  0x8b, 0x9b, 0xab, 0xbb, 0xcb, 0xdb, 0xeb, 0xfb,
                   2265:  0x0c, 0x1c, 0x2c, 0x3c, 0x4c, 0x5c, 0x6c, 0x7c,
                   2266:  0x8c, 0x9c, 0xac, 0xbc, 0xcc, 0xdc, 0xec, 0xfc,
                   2267:  0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d,
                   2268:  0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd,
                   2269:  0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e,
                   2270:  0x8e, 0x9e, 0xae, 0xbe, 0xce, 0xde, 0xee, 0xfe,
                   2271:  0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
                   2272:  0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
                   2273: };
                   2274: 
                   2275: void
                   2276: pixreverse(uchar *p, int len, int ldepth)
                   2277: {
                   2278:        uchar *e;
                   2279:        uchar *tab;
                   2280: 
                   2281:        switch(ldepth){
                   2282:        case 0:
                   2283:                tab = revtab0;
                   2284:                break;
                   2285:        case 1:
                   2286:                tab = revtab1;
                   2287:                break;
                   2288:        case 2:
                   2289:                tab = revtab2;
                   2290:                break;
                   2291:        default:
                   2292:                return;
                   2293:        }
                   2294: 
                   2295:        for(e = p + len; p < e; p++)
                   2296:                *p = tab[*p];
                   2297: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.