ref: a920c765f2b4130590fb5971a50690b21664957a
dir: /os/port/swcursor.c/
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "io.h" #include <draw.h> #include <memdraw.h> #include <cursor.h> #include "screen.h" typedef struct SWcursor SWcursor; /* * Software cursor code: done by hand, might be better to use memdraw */ struct SWcursor { ulong *fb; /* screen frame buffer */ Rectangle r; int d; /* ldepth of screen */ int width; /* width of screen in ulongs */ int x; int y; int hotx; int hoty; uchar cbwid; /* cursor byte width */ uchar f; /* flags */ uchar cwid; uchar chgt; int hidecount; uchar data[CURSWID*CURSHGT]; uchar mask[CURSWID*CURSHGT]; uchar save[CURSWID*CURSHGT]; }; enum { CUR_ENA = 0x01, /* cursor is enabled */ CUR_DRW = 0x02, /* cursor is currently drawn */ CUR_SWP = 0x10, /* bit swap */ }; static Rectangle cursoroffrect; static int cursorisoff; static void swcursorflush(int, int); static void swcurs_draw_or_undraw(SWcursor *); static void cursorupdate0(void) { int inrect, x, y; Point m; m = mousexy(); x = m.x - swc->hotx; y = m.y - swc->hoty; inrect = (x >= cursoroffrect.min.x && x < cursoroffrect.max.x && y >= cursoroffrect.min.y && y < cursoroffrect.max.y); if (cursorisoff == inrect) return; cursorisoff = inrect; if (inrect) swcurs_hide(swc); else { swc->hidecount = 0; swcurs_draw_or_undraw(swc); } swcursorflush(m.x, m.y); } void cursorupdate(Rectangle r) { lock(vd); r.min.x -= 16; r.min.y -= 16; cursoroffrect = r; if (swc != nil) cursorupdate0(); unlock(vd); } void cursorenable(void) { Point m; lock(vd); if(swc != nil) { swcurs_enable(swc); m = mousexy(); swcursorflush(m.x, m.y); } unlock(vd); } void cursordisable(void) { Point m; lock(vd); if(swc != nil) { swcurs_disable(swc); m = mousexy(); swcursorflush(m.x, m.y); } unlock(vd); } void swcursupdate(int oldx, int oldy, int x, int y) { if(!canlock(vd)) return; /* if can't lock, don't wake up stuff */ if(x < gscreen->r.min.x) x = gscreen->r.min.x; if(x >= gscreen->r.max.x) x = gscreen->r.max.x; if(y < gscreen->r.min.y) y = gscreen->r.min.y; if(y >= gscreen->r.max.y) y = gscreen->r.max.y; if(swc != nil) { swcurs_hide(swc); swc->x = x; swc->y = y; cursorupdate0(); swcurs_unhide(swc); swcursorflush(oldx, oldy); swcursorflush(x, y); } unlock(vd); } void drawcursor(Drawcursor* c) { Point p, m; Cursor curs, *cp; int j, i, h, bpl; uchar *bc, *bs, *cclr, *cset; if(swc == nil) return; /* Set the default system cursor */ if(c == nil || c->data == nil){ swcurs_disable(swc); return; } else { cp = &curs; p.x = c->hotx; p.y = c->hoty; cp->offset = p; bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 1); h = (c->maxy-c->miny)/2; if(h > 16) h = 16; bc = c->data; bs = c->data + h*bpl; cclr = cp->clr; cset = cp->set; for(i = 0; i < h; i++) { for(j = 0; j < 2; j++) { cclr[j] = bc[j]; cset[j] = bs[j]; } bc += bpl; bs += bpl; cclr += 2; cset += 2; } } swcurs_load(swc, cp); m = mousexy(); swcursorflush(m.x, m.y); swcurs_enable(swc); } SWcursor* swcurs_create(ulong *fb, int width, int ldepth, Rectangle r, int bitswap) { SWcursor *swc; swc = (SWcursor*)malloc(sizeof(SWcursor)); swc->fb = fb; swc->r = r; swc->d = ldepth; swc->width = width; swc->f = bitswap ? CUR_SWP : 0; swc->x = swc->y = 0; swc->hotx = swc->hoty = 0; swc->hidecount = 0; return swc; } void swcurs_destroy(SWcursor *swc) { swcurs_disable(swc); free(swc); } static void swcursorflush(int x, int y) { Rectangle r; /* XXX a little too paranoid here */ r.min.x = x-16; r.min.y = y-16; r.max.x = x+17; r.max.y = y+17; flushmemscreen(r); } static void swcurs_draw_or_undraw(SWcursor *swc) { uchar *p; uchar *cs; int w, vw; int x1 = swc->r.min.x; int y1 = swc->r.min.y; int x2 = swc->r.max.x; int y2 = swc->r.max.y; int xp = swc->x - swc->hotx; int yp = swc->y - swc->hoty; int ofs; if(((swc->f & CUR_ENA) && (swc->hidecount <= 0)) == ((swc->f & CUR_DRW) != 0)) return; w = swc->cbwid*BI2BY/(1 << swc->d); x1 = xp < x1 ? x1 : xp; y1 = yp < y1 ? y1 : yp; x2 = xp+w >= x2 ? x2 : xp+w; y2 = yp+swc->chgt >= y2 ? y2 : yp+swc->chgt; if(x2 <= x1 || y2 <= y1) return; p = (uchar*)(swc->fb + swc->width*y1) + x1*(1 << swc->d)/BI2BY; y2 -= y1; x2 = (x2-x1)*(1 << swc->d)/BI2BY; vw = swc->width*BY2WD - x2; w = swc->cbwid - x2; ofs = swc->cbwid*(y1-yp)+(x1-xp); cs = swc->save + ofs; if((swc->f ^= CUR_DRW) & CUR_DRW) { uchar *cm = swc->mask + ofs; uchar *cd = swc->data + ofs; while(y2--) { x1 = x2; while(x1--) { *p = ((*cs++ = *p) & *cm++) ^ *cd++; p++; } cs += w; cm += w; cd += w; p += vw; } } else { while(y2--) { x1 = x2; while(x1--) *p++ = *cs++; cs += w; p += vw; } } } void swcurs_hide(SWcursor *swc) { ++swc->hidecount; swcurs_draw_or_undraw(swc); } void swcurs_unhide(SWcursor *swc) { if (--swc->hidecount < 0) swc->hidecount = 0; swcurs_draw_or_undraw(swc); } void swcurs_enable(SWcursor *swc) { swc->f |= CUR_ENA; swcurs_draw_or_undraw(swc); } void swcurs_disable(SWcursor *swc) { swc->f &= ~CUR_ENA; swcurs_draw_or_undraw(swc); } void swcurs_load(SWcursor *swc, Cursor *c) { int i, k; uchar *bc, *bs, *cd, *cm; static uchar bdv[4] = {0,Backgnd,Foregnd,0xff}; static uchar bmv[4] = {0xff,0,0,0xff}; int bits = 1<<swc->d; uchar mask = (1<<bits)-1; int bswp = (swc->f&CUR_SWP) ? 8-bits : 0; bc = c->clr; bs = c->set; swcurs_hide(swc); cd = swc->data; cm = swc->mask; swc->hotx = c->offset.x; swc->hoty = c->offset.y; swc->chgt = CURSHGT; swc->cwid = CURSWID; swc->cbwid = CURSWID*(1<<swc->d)/BI2BY; for(i = 0; i < CURSWID/BI2BY*CURSHGT; i++) { uchar bcb = *bc++; uchar bsb = *bs++; for(k=0; k<BI2BY;) { uchar cdv = 0; uchar cmv = 0; int z; for(z=0; z<BI2BY; z += bits) { int n = ((bsb&(0x80))|((bcb&(0x80))<<1))>>7; int s = z^bswp; cdv |= (bdv[n]&mask) << s; cmv |= (bmv[n]&mask) << s; bcb <<= 1; bsb <<= 1; k++; } *cd++ = cdv; *cm++ = cmv; } } swcurs_unhide(swc); }