ref: 94443daf8e248e65afc8d3f17f26efea22748b51
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);
}