reduce software cursor flickering
the software cursor starts flickering and reacts bumby if a process spends most of its time with drawlock acquired because the timer interrupt thats supposed to redraw the cursor fails to acquire the lock at the time the timer fires. instead of trying to draw the cursor on the screen from a timer interrupt 30 times per second, devmouse now creates a process calling cursoron() and cursoroff() when the cursor needs to be redrawn. this allows the swcursor to schedule a redraw while holding the drawlock in swcursoravoid() and cursoron()/cursoroff() are now able to wait for a qlock (drawlock) because they get called from process context. the overall responsiveness is also improved with this change as the cursor redraw rate isnt limited to 30 times a second anymore.
This commit is contained in:
parent
58e500f4a7
commit
3045d63969
17 changed files with 303 additions and 614 deletions
|
@ -64,7 +64,6 @@ extern void setpower(int, int);
|
|||
extern void setr13(int, u32int*);
|
||||
extern int splfhi(void);
|
||||
extern int splflo(void);
|
||||
extern void swcursorinit(void);
|
||||
extern int tas(void *);
|
||||
extern void touser(uintptr);
|
||||
extern void trapinit(void);
|
||||
|
|
|
@ -249,8 +249,6 @@ main(void)
|
|||
clockinit();
|
||||
printinit();
|
||||
timersinit();
|
||||
if(conf.monitor)
|
||||
swcursorinit();
|
||||
cpuidprint();
|
||||
archreset();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ dev
|
|||
cap
|
||||
fs
|
||||
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno
|
||||
draw screen
|
||||
draw screen swcursor
|
||||
mouse mouse
|
||||
uart
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ dev
|
|||
cap
|
||||
fs
|
||||
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno
|
||||
draw screen
|
||||
draw screen swcursor
|
||||
mouse mouse
|
||||
uart
|
||||
|
||||
|
|
|
@ -69,203 +69,32 @@ static void myscreenputs(char *s, int n);
|
|||
static void screenputc(char *buf);
|
||||
static void screenwin(void);
|
||||
|
||||
/*
|
||||
* Software cursor.
|
||||
*/
|
||||
static int swvisible; /* is the cursor visible? */
|
||||
static int swenabled; /* is the cursor supposed to be on the screen? */
|
||||
static Memimage *swback; /* screen under cursor */
|
||||
static Memimage *swimg; /* cursor image */
|
||||
static Memimage *swmask; /* cursor mask */
|
||||
static Memimage *swimg1;
|
||||
static Memimage *swmask1;
|
||||
|
||||
static Point swoffset;
|
||||
static Rectangle swrect; /* screen rectangle in swback */
|
||||
static Point swpt; /* desired cursor location */
|
||||
static Point swvispt; /* actual cursor location */
|
||||
static int swvers; /* incremented each time cursor image changes */
|
||||
static int swvisvers; /* the version on the screen */
|
||||
|
||||
/*
|
||||
* called with drawlock locked for us, most of the time.
|
||||
* kernel prints at inopportune times might mean we don't
|
||||
* hold the lock, but memimagedraw is now reentrant so
|
||||
* that should be okay: worst case we get cursor droppings.
|
||||
*/
|
||||
static void
|
||||
swcursorhide(void)
|
||||
void
|
||||
cursoron(void)
|
||||
{
|
||||
if(swvisible == 0)
|
||||
return;
|
||||
if(swback == nil)
|
||||
return;
|
||||
swvisible = 0;
|
||||
memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
|
||||
flushmemscreen(swrect);
|
||||
}
|
||||
|
||||
static void
|
||||
swcursoravoid(Rectangle r)
|
||||
{
|
||||
if(swvisible && rectXrect(r, swrect))
|
||||
swcursorhide();
|
||||
}
|
||||
|
||||
static void
|
||||
swcursordraw(void)
|
||||
{
|
||||
int dounlock;
|
||||
|
||||
if(swvisible)
|
||||
return;
|
||||
if(swenabled == 0)
|
||||
return;
|
||||
if(swback == nil || swimg1 == nil || swmask1 == nil)
|
||||
return;
|
||||
dounlock = canqlock(&drawlock);
|
||||
swvispt = swpt;
|
||||
swvisvers = swvers;
|
||||
swrect = rectaddpt(Rect(0,0,16,16), swvispt);
|
||||
memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
|
||||
memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
|
||||
flushmemscreen(swrect);
|
||||
swvisible = 1;
|
||||
if(dounlock)
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
|
||||
int
|
||||
cursoron(int dolock)
|
||||
{
|
||||
int retry;
|
||||
|
||||
if (dolock)
|
||||
lock(&cursor);
|
||||
if (canqlock(&drawlock)) {
|
||||
retry = 0;
|
||||
swcursorhide();
|
||||
swcursordraw();
|
||||
qunlock(&drawlock);
|
||||
} else
|
||||
retry = 1;
|
||||
if (dolock)
|
||||
unlock(&cursor);
|
||||
return retry;
|
||||
qlock(&drawlock);
|
||||
lock(&cursor);
|
||||
swcursorhide();
|
||||
swcursordraw(mousexy());
|
||||
unlock(&cursor);
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
|
||||
void
|
||||
cursoroff(int dolock)
|
||||
cursoroff(void)
|
||||
{
|
||||
if (dolock)
|
||||
lock(&cursor);
|
||||
qlock(&drawlock);
|
||||
lock(&cursor);
|
||||
swcursorhide();
|
||||
if (dolock)
|
||||
unlock(&cursor);
|
||||
}
|
||||
|
||||
static void
|
||||
swload(Cursor *curs)
|
||||
{
|
||||
uchar *ip, *mp;
|
||||
int i, j, set, clr;
|
||||
|
||||
if(!swimg || !swmask || !swimg1 || !swmask1)
|
||||
return;
|
||||
/*
|
||||
* Build cursor image and mask.
|
||||
* Image is just the usual cursor image
|
||||
* but mask is a transparent alpha mask.
|
||||
*
|
||||
* The 16x16x8 memimages do not have
|
||||
* padding at the end of their scan lines.
|
||||
*/
|
||||
ip = byteaddr(swimg, ZP);
|
||||
mp = byteaddr(swmask, ZP);
|
||||
for(i=0; i<32; i++){
|
||||
set = curs->set[i];
|
||||
clr = curs->clr[i];
|
||||
for(j=0x80; j; j>>=1){
|
||||
*ip++ = set&j ? 0x00 : 0xFF;
|
||||
*mp++ = (clr|set)&j ? 0xFF : 0x00;
|
||||
}
|
||||
}
|
||||
swoffset = curs->offset;
|
||||
swvers++;
|
||||
memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
|
||||
memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
|
||||
unlock(&cursor);
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
|
||||
/* called from devmouse */
|
||||
void
|
||||
setcursor(Cursor* curs)
|
||||
{
|
||||
cursoroff(0);
|
||||
swload(curs);
|
||||
cursoron(0);
|
||||
}
|
||||
|
||||
static int
|
||||
swmove(Point p)
|
||||
{
|
||||
swpt = addpt(p, swoffset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
swcursorclock(void)
|
||||
{
|
||||
int x;
|
||||
|
||||
if(!swenabled)
|
||||
return;
|
||||
swmove(mousexy());
|
||||
if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
|
||||
return;
|
||||
|
||||
x = splhi();
|
||||
if(swenabled)
|
||||
if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
|
||||
if(canqlock(&drawlock)){
|
||||
swcursorhide();
|
||||
swcursordraw();
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
splx(x);
|
||||
}
|
||||
|
||||
void
|
||||
swcursorinit(void)
|
||||
{
|
||||
static int init;
|
||||
|
||||
if(!init){
|
||||
init = 1;
|
||||
addclock0link(swcursorclock, 10);
|
||||
swenabled = 1;
|
||||
}
|
||||
if(swback){
|
||||
freememimage(swback);
|
||||
freememimage(swmask);
|
||||
freememimage(swmask1);
|
||||
freememimage(swimg);
|
||||
freememimage(swimg1);
|
||||
}
|
||||
|
||||
swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
|
||||
swmask = allocmemimage(Rect(0,0,16,16), GREY8);
|
||||
swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
||||
swimg = allocmemimage(Rect(0,0,16,16), GREY8);
|
||||
swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
||||
if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
|
||||
print("software cursor: allocmemimage fails\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memfillcolor(swmask, DOpaque);
|
||||
memfillcolor(swmask1, DOpaque);
|
||||
memfillcolor(swimg, DBlack);
|
||||
memfillcolor(swimg1, DBlack);
|
||||
swcursorload(curs);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -348,6 +177,7 @@ screeninit(void)
|
|||
memdefont = getmemdefont();
|
||||
screenwin();
|
||||
screenputs = myscreenputs;
|
||||
swcursorinit();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -21,16 +21,24 @@ extern Cursor arrow;
|
|||
/* mouse.c */
|
||||
extern void mousectl(Cmdbuf*);
|
||||
extern void mouseresize(void);
|
||||
extern void mouseredraw(void);
|
||||
|
||||
/* screen.c */
|
||||
extern void blankscreen(int);
|
||||
extern void flushmemscreen(Rectangle);
|
||||
extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*);
|
||||
extern int cursoron(int);
|
||||
extern void cursoroff(int);
|
||||
extern void cursoron(void);
|
||||
extern void cursoroff(void);
|
||||
extern void setcursor(Cursor*);
|
||||
|
||||
/* devdraw.c */
|
||||
extern QLock drawlock;
|
||||
|
||||
#define ishwimage(i) 1 /* for ../port/devdraw.c */
|
||||
|
||||
/* swcursor.c */
|
||||
void swcursorhide(void);
|
||||
void swcursoravoid(Rectangle);
|
||||
void swcursordraw(Point);
|
||||
void swcursorload(Cursor *);
|
||||
void swcursorinit(void);
|
||||
|
|
|
@ -24,7 +24,7 @@ dev
|
|||
ether netif
|
||||
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno
|
||||
|
||||
draw screen
|
||||
draw screen swcursor
|
||||
dss
|
||||
mouse
|
||||
|
||||
|
|
|
@ -346,174 +346,33 @@ screenpower(int on)
|
|||
blankscreen(on == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* called with drawlock locked for us, most of the time.
|
||||
* kernel prints at inopportune times might mean we don't
|
||||
* hold the lock, but memimagedraw is now reentrant so
|
||||
* that should be okay: worst case we get cursor droppings.
|
||||
*/
|
||||
void
|
||||
swcursorhide(void)
|
||||
cursoron(void)
|
||||
{
|
||||
if(swvisible == 0)
|
||||
return;
|
||||
if(swback == nil)
|
||||
return;
|
||||
swvisible = 0;
|
||||
memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
|
||||
flushmemscreen(swrect);
|
||||
}
|
||||
|
||||
void
|
||||
swcursoravoid(Rectangle r)
|
||||
{
|
||||
if(swvisible && rectXrect(r, swrect))
|
||||
swcursorhide();
|
||||
}
|
||||
|
||||
void
|
||||
swcursordraw(void)
|
||||
{
|
||||
if(swvisible)
|
||||
return;
|
||||
if(swenabled == 0)
|
||||
return;
|
||||
if(swback == nil || swimg1 == nil || swmask1 == nil)
|
||||
return;
|
||||
// assert(!canqlock(&drawlock)); // assertion fails on omap
|
||||
swvispt = swpt;
|
||||
swvisvers = swvers;
|
||||
swrect = rectaddpt(Rect(0,0,16,16), swvispt);
|
||||
memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
|
||||
memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
|
||||
flushmemscreen(swrect);
|
||||
swvisible = 1;
|
||||
}
|
||||
|
||||
int
|
||||
cursoron(int dolock)
|
||||
{
|
||||
if (dolock)
|
||||
lock(&oscreen);
|
||||
cursoroff(0);
|
||||
swcursordraw();
|
||||
if (dolock)
|
||||
unlock(&oscreen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cursoroff(int dolock)
|
||||
{
|
||||
if (dolock)
|
||||
lock(&oscreen);
|
||||
qlock(&drawlock);
|
||||
lock(&cursor);
|
||||
swcursorhide();
|
||||
if (dolock)
|
||||
unlock(&oscreen);
|
||||
swcursordraw(mousexy());
|
||||
unlock(&cursor);
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
|
||||
void
|
||||
swload(Cursor *curs)
|
||||
cursoroff(void)
|
||||
{
|
||||
uchar *ip, *mp;
|
||||
int i, j, set, clr;
|
||||
|
||||
if(!swimg || !swmask || !swimg1 || !swmask1)
|
||||
return;
|
||||
/*
|
||||
* Build cursor image and mask.
|
||||
* Image is just the usual cursor image
|
||||
* but mask is a transparent alpha mask.
|
||||
*
|
||||
* The 16x16x8 memimages do not have
|
||||
* padding at the end of their scan lines.
|
||||
*/
|
||||
ip = byteaddr(swimg, ZP);
|
||||
mp = byteaddr(swmask, ZP);
|
||||
for(i=0; i<32; i++){
|
||||
set = curs->set[i];
|
||||
clr = curs->clr[i];
|
||||
for(j=0x80; j; j>>=1){
|
||||
*ip++ = set&j ? 0x00 : 0xFF;
|
||||
*mp++ = (clr|set)&j ? 0xFF : 0x00;
|
||||
}
|
||||
}
|
||||
swoffset = curs->offset;
|
||||
swvers++;
|
||||
memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
|
||||
memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
|
||||
qlock(&drawlock);
|
||||
lock(&cursor);
|
||||
swcursorhide();
|
||||
unlock(&cursor);
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
|
||||
/* called from devmouse */
|
||||
void
|
||||
setcursor(Cursor* curs)
|
||||
{
|
||||
cursoroff(1);
|
||||
oscreen.Cursor = *curs;
|
||||
swload(curs);
|
||||
cursoron(1);
|
||||
}
|
||||
|
||||
int
|
||||
swmove(Point p)
|
||||
{
|
||||
swpt = addpt(p, swoffset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
swcursorclock(void)
|
||||
{
|
||||
int x;
|
||||
|
||||
if(!swenabled)
|
||||
return;
|
||||
swmove(mousexy());
|
||||
if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
|
||||
return;
|
||||
|
||||
x = splhi();
|
||||
if(swenabled)
|
||||
if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
|
||||
if(canqlock(&drawlock)){
|
||||
swcursorhide();
|
||||
swcursordraw();
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
splx(x);
|
||||
}
|
||||
|
||||
void
|
||||
swcursorinit(void)
|
||||
{
|
||||
static int init;
|
||||
|
||||
if(!init){
|
||||
init = 1;
|
||||
addclock0link(swcursorclock, 10);
|
||||
}
|
||||
if(swback){
|
||||
freememimage(swback);
|
||||
freememimage(swmask);
|
||||
freememimage(swmask1);
|
||||
freememimage(swimg);
|
||||
freememimage(swimg1);
|
||||
}
|
||||
|
||||
swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
|
||||
swmask = allocmemimage(Rect(0,0,16,16), GREY8);
|
||||
swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
||||
swimg = allocmemimage(Rect(0,0,16,16), GREY8);
|
||||
swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
||||
if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
|
||||
print("software cursor: allocmemimage fails\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memfillcolor(swmask, DOpaque);
|
||||
memfillcolor(swmask1, DOpaque);
|
||||
memfillcolor(swimg, DBlack);
|
||||
memfillcolor(swimg1, DBlack);
|
||||
swcursorload(curs);
|
||||
}
|
||||
|
||||
/* called from main and possibly later from devdss to change resolution */
|
||||
|
|
|
@ -20,12 +20,13 @@ extern Point mousexy(void);
|
|||
|
||||
extern void mouseaccelerate(int);
|
||||
extern void mouseresize(void);
|
||||
extern void mouseredraw(void);
|
||||
|
||||
/* screen.c */
|
||||
extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*);
|
||||
extern void flushmemscreen(Rectangle);
|
||||
extern int cursoron(int);
|
||||
extern void cursoroff(int);
|
||||
extern void cursoron(void);
|
||||
extern void cursoroff(void);
|
||||
extern void setcursor(Cursor*);
|
||||
extern int screensize(int, int, int, ulong);
|
||||
extern int screenaperture(int, int);
|
||||
|
@ -49,6 +50,13 @@ extern QLock drawlock;
|
|||
|
||||
#define ishwimage(i) 0 /* for ../port/devdraw.c */
|
||||
|
||||
/* swcursor.c */
|
||||
void swcursorhide(void);
|
||||
void swcursoravoid(Rectangle);
|
||||
void swcursordraw(Point);
|
||||
void swcursorload(Cursor *);
|
||||
void swcursorinit(void);
|
||||
|
||||
/* for communication between devdss.c and screen.c */
|
||||
|
||||
enum {
|
||||
|
@ -93,7 +101,6 @@ struct Settings {
|
|||
};
|
||||
|
||||
struct OScreen {
|
||||
Lock;
|
||||
Cursor;
|
||||
Settings *settings;
|
||||
int open;
|
||||
|
|
|
@ -349,7 +349,7 @@ vgactl(Cmdbuf *cb)
|
|||
if(chantodepth(chan) != z)
|
||||
error("depth, channel do not match");
|
||||
|
||||
cursoroff(1);
|
||||
cursoroff();
|
||||
deletescreenimage();
|
||||
if(screensize(x, y, z, chan))
|
||||
error(Egreg);
|
||||
|
@ -397,7 +397,7 @@ vgactl(Cmdbuf *cb)
|
|||
y = scr->gscreen->r.max.y;
|
||||
z = scr->gscreen->depth;
|
||||
chan = scr->gscreen->chan;
|
||||
cursoroff(1);
|
||||
cursoroff();
|
||||
deletescreenimage();
|
||||
if(screensize(x, y, z, chan))
|
||||
error(Egreg);
|
||||
|
@ -411,7 +411,7 @@ vgactl(Cmdbuf *cb)
|
|||
hwaccel = !scr->softscreen && (scr->scroll || scr->fill);
|
||||
vgascreenwin(scr);
|
||||
resetscreenimage();
|
||||
cursoron(1);
|
||||
cursoron();
|
||||
return;
|
||||
|
||||
case CMlinear:
|
||||
|
|
|
@ -23,7 +23,7 @@ dev
|
|||
ether netif
|
||||
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
|
||||
|
||||
draw screen vga vgax
|
||||
draw screen vga vgax swcursor
|
||||
mouse mouse
|
||||
kbd
|
||||
vga
|
||||
|
|
|
@ -21,7 +21,7 @@ dev
|
|||
ether netif
|
||||
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
|
||||
|
||||
draw screen vga vgax
|
||||
draw screen vga vgax swcursor
|
||||
mouse mouse
|
||||
kbd
|
||||
vga
|
||||
|
|
|
@ -23,7 +23,7 @@ Memimage *gscreen;
|
|||
|
||||
VGAscr vgascreen[1];
|
||||
|
||||
Cursor arrow = {
|
||||
Cursor arrow = {
|
||||
{ -1, -1 },
|
||||
{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
|
||||
0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
|
||||
|
@ -37,8 +37,6 @@ Cursor arrow = {
|
|||
},
|
||||
};
|
||||
|
||||
int didswcursorinit;
|
||||
|
||||
int
|
||||
screensize(int x, int y, int, ulong chan)
|
||||
{
|
||||
|
@ -101,8 +99,7 @@ screensize(int x, int y, int, ulong chan)
|
|||
poperror();
|
||||
|
||||
drawcmap();
|
||||
if(didswcursorinit)
|
||||
swcursorinit();
|
||||
swcursorinit();
|
||||
|
||||
qunlock(&drawlock);
|
||||
poperror();
|
||||
|
@ -327,27 +324,63 @@ setcolor(ulong p, ulong r, ulong g, ulong b)
|
|||
return setpalette(p, r, g, b);
|
||||
}
|
||||
|
||||
int
|
||||
cursoron(int dolock)
|
||||
void
|
||||
swenable(VGAscr*)
|
||||
{
|
||||
VGAscr *scr;
|
||||
int v;
|
||||
|
||||
scr = &vgascreen[0];
|
||||
if(scr->cur == nil || scr->cur->move == nil)
|
||||
return 0;
|
||||
|
||||
if(dolock)
|
||||
lock(&cursor);
|
||||
v = scr->cur->move(scr, mousexy());
|
||||
if(dolock)
|
||||
unlock(&cursor);
|
||||
|
||||
return v;
|
||||
swcursorload(&arrow);
|
||||
}
|
||||
|
||||
void
|
||||
cursoroff(int)
|
||||
swdisable(VGAscr*)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
swload(VGAscr*, Cursor *curs)
|
||||
{
|
||||
swcursorload(curs);
|
||||
}
|
||||
|
||||
int
|
||||
swmove(VGAscr*, Point p)
|
||||
{
|
||||
swcursorhide();
|
||||
swcursordraw(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
VGAcur swcursor =
|
||||
{
|
||||
"soft",
|
||||
swenable,
|
||||
swdisable,
|
||||
swload,
|
||||
swmove,
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
cursoron(void)
|
||||
{
|
||||
VGAscr *scr;
|
||||
VGAcur *cur;
|
||||
|
||||
scr = &vgascreen[0];
|
||||
cur = scr->cur;
|
||||
if(cur == nil || cur->move == nil)
|
||||
return;
|
||||
|
||||
if(cur == &swcursor)
|
||||
qlock(&drawlock);
|
||||
lock(&cursor);
|
||||
cur->move(scr, mousexy());
|
||||
unlock(&cursor);
|
||||
if(cur == &swcursor)
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
|
||||
void
|
||||
cursoroff(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -532,196 +565,3 @@ vgalinearaddr(VGAscr *scr, ulong paddr, int size)
|
|||
poperror();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Software cursor.
|
||||
*/
|
||||
int swvisible; /* is the cursor visible? */
|
||||
int swenabled; /* is the cursor supposed to be on the screen? */
|
||||
Memimage* swback; /* screen under cursor */
|
||||
Memimage* swimg; /* cursor image */
|
||||
Memimage* swmask; /* cursor mask */
|
||||
Memimage* swimg1;
|
||||
Memimage* swmask1;
|
||||
|
||||
Point swoffset;
|
||||
Rectangle swrect; /* screen rectangle in swback */
|
||||
Point swpt; /* desired cursor location */
|
||||
Point swvispt; /* actual cursor location */
|
||||
int swvers; /* incremented each time cursor image changes */
|
||||
int swvisvers; /* the version on the screen */
|
||||
|
||||
/*
|
||||
* called with drawlock locked for us, most of the time.
|
||||
* kernel prints at inopportune times might mean we don't
|
||||
* hold the lock, but memimagedraw is now reentrant so
|
||||
* that should be okay: worst case we get cursor droppings.
|
||||
*/
|
||||
void
|
||||
swcursorhide(void)
|
||||
{
|
||||
if(swvisible == 0)
|
||||
return;
|
||||
if(swback == nil)
|
||||
return;
|
||||
swvisible = 0;
|
||||
memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
|
||||
flushmemscreen(swrect);
|
||||
}
|
||||
|
||||
void
|
||||
swcursoravoid(Rectangle r)
|
||||
{
|
||||
if(swvisible && rectXrect(r, swrect))
|
||||
swcursorhide();
|
||||
}
|
||||
|
||||
void
|
||||
swcursordraw(void)
|
||||
{
|
||||
if(swvisible)
|
||||
return;
|
||||
if(swenabled == 0)
|
||||
return;
|
||||
if(swback == nil || swimg1 == nil || swmask1 == nil)
|
||||
return;
|
||||
assert(!canqlock(&drawlock));
|
||||
swvispt = swpt;
|
||||
swvisvers = swvers;
|
||||
swrect = rectaddpt(Rect(0,0,16,16), swvispt);
|
||||
memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
|
||||
memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
|
||||
flushmemscreen(swrect);
|
||||
swvisible = 1;
|
||||
}
|
||||
|
||||
void
|
||||
swload(VGAscr*, Cursor *curs)
|
||||
{
|
||||
uchar *ip, *mp;
|
||||
int i, j, set, clr;
|
||||
|
||||
if(!swimg || !swmask || !swimg1 || !swmask1)
|
||||
return;
|
||||
/*
|
||||
* Build cursor image and mask.
|
||||
* Image is just the usual cursor image
|
||||
* but mask is a transparent alpha mask.
|
||||
*
|
||||
* The 16x16x8 memimages do not have
|
||||
* padding at the end of their scan lines.
|
||||
*/
|
||||
ip = byteaddr(swimg, ZP);
|
||||
mp = byteaddr(swmask, ZP);
|
||||
for(i=0; i<32; i++){
|
||||
set = curs->set[i];
|
||||
clr = curs->clr[i];
|
||||
for(j=0x80; j; j>>=1){
|
||||
*ip++ = set&j ? 0x00 : 0xFF;
|
||||
*mp++ = (clr|set)&j ? 0xFF : 0x00;
|
||||
}
|
||||
}
|
||||
swoffset = curs->offset;
|
||||
swvers++;
|
||||
memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
|
||||
memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
|
||||
}
|
||||
|
||||
int
|
||||
swmove(VGAscr*, Point p)
|
||||
{
|
||||
swpt = addpt(p, swoffset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
swcursorclock(void)
|
||||
{
|
||||
int x;
|
||||
|
||||
if(!swenabled)
|
||||
return;
|
||||
if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
|
||||
return;
|
||||
|
||||
x = splhi();
|
||||
if(swenabled)
|
||||
if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
|
||||
if(canqlock(&drawlock)){
|
||||
swcursorhide();
|
||||
swcursordraw();
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
splx(x);
|
||||
}
|
||||
|
||||
void
|
||||
swcursorinit(void)
|
||||
{
|
||||
static int init;
|
||||
VGAscr *scr;
|
||||
|
||||
didswcursorinit = 1;
|
||||
if(!init){
|
||||
init = 1;
|
||||
addclock0link(swcursorclock, 10);
|
||||
}
|
||||
|
||||
scr = &vgascreen[0];
|
||||
if(scr->gscreen==nil)
|
||||
return;
|
||||
|
||||
if(swback){
|
||||
freememimage(swback);
|
||||
freememimage(swmask);
|
||||
freememimage(swmask1);
|
||||
freememimage(swimg);
|
||||
freememimage(swimg1);
|
||||
}
|
||||
swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
|
||||
swmask = allocmemimage(Rect(0,0,16,16), GREY8);
|
||||
swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
||||
swimg = allocmemimage(Rect(0,0,16,16), GREY8);
|
||||
swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
||||
if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil)
|
||||
print("software cursor: allocmemimage fails");
|
||||
memfillcolor(swback, DTransparent);
|
||||
memfillcolor(swmask, DOpaque);
|
||||
memfillcolor(swmask1, DOpaque);
|
||||
memfillcolor(swimg, DBlack);
|
||||
memfillcolor(swimg1, DBlack);
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to lock drawlock for ourselves.
|
||||
*/
|
||||
void
|
||||
swenable(VGAscr *scr)
|
||||
{
|
||||
swenabled = 1;
|
||||
if(canqlock(&drawlock)){
|
||||
swload(scr, &arrow);
|
||||
swcursordraw();
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
swdisable(VGAscr*)
|
||||
{
|
||||
swenabled = 0;
|
||||
if(canqlock(&drawlock)){
|
||||
swcursorhide();
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
}
|
||||
|
||||
VGAcur swcursor =
|
||||
{
|
||||
"soft",
|
||||
swenable,
|
||||
swdisable,
|
||||
swload,
|
||||
swmove,
|
||||
};
|
||||
|
|
|
@ -132,6 +132,7 @@ enum {
|
|||
/* mouse.c */
|
||||
extern void mousectl(Cmdbuf*);
|
||||
extern void mouseresize(void);
|
||||
extern void mouseredraw(void);
|
||||
|
||||
/* screen.c */
|
||||
extern int hwaccel; /* use hw acceleration; default on */
|
||||
|
@ -140,8 +141,8 @@ extern int panning; /* use virtual screen panning; default off */
|
|||
extern void addvgaseg(char*, ulong, ulong);
|
||||
extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*);
|
||||
extern void flushmemscreen(Rectangle);
|
||||
extern int cursoron(int);
|
||||
extern void cursoroff(int);
|
||||
extern void cursoron(void);
|
||||
extern void cursoroff(void);
|
||||
extern void setcursor(Cursor*);
|
||||
extern int screensize(int, int, int, ulong);
|
||||
extern int screenaperture(int, int);
|
||||
|
@ -176,3 +177,10 @@ extern void vgablank(VGAscr*, int);
|
|||
extern Lock vgascreenlock;
|
||||
|
||||
#define ishwimage(i) (vgascreen[0].gscreendata && (i)->data->bdata == vgascreen[0].gscreendata->bdata)
|
||||
|
||||
/* swcursor.c */
|
||||
void swcursorhide(void);
|
||||
void swcursoravoid(Rectangle);
|
||||
void swcursordraw(Point);
|
||||
void swcursorload(Cursor *);
|
||||
void swcursorinit(void);
|
||||
|
|
|
@ -33,16 +33,13 @@ struct Mouseinfo
|
|||
{
|
||||
Lock;
|
||||
Mousestate;
|
||||
int dx;
|
||||
int dy;
|
||||
int track; /* dx & dy updated */
|
||||
int redraw; /* update cursor on screen */
|
||||
Rendez redrawr; /* wait for cursor screen updates */
|
||||
ulong lastcounter; /* value when /dev/mouse read */
|
||||
ulong lastresize;
|
||||
ulong resize;
|
||||
Rendez r;
|
||||
Ref;
|
||||
QLock;
|
||||
int open;
|
||||
int acceleration;
|
||||
int maxacc;
|
||||
|
@ -77,8 +74,7 @@ Cursor curs;
|
|||
|
||||
void Cursortocursor(Cursor*);
|
||||
int mousechanged(void*);
|
||||
|
||||
static void mouseclock(void);
|
||||
void mouseredraw(void);
|
||||
|
||||
enum{
|
||||
Qdir,
|
||||
|
@ -114,8 +110,6 @@ mousereset(void)
|
|||
|
||||
curs = arrow;
|
||||
Cursortocursor(&arrow);
|
||||
/* redraw cursor about 30 times per second */
|
||||
addclock0link(mouseclock, 33);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -129,6 +123,8 @@ mousedevgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void mouseproc(void*);
|
||||
|
||||
static void
|
||||
mouseinit(void)
|
||||
{
|
||||
|
@ -137,8 +133,10 @@ mouseinit(void)
|
|||
|
||||
curs = arrow;
|
||||
Cursortocursor(&arrow);
|
||||
cursoron(1);
|
||||
cursoron();
|
||||
mousetime = seconds();
|
||||
|
||||
kproc("mouse", mouseproc, 0);
|
||||
}
|
||||
|
||||
static Chan*
|
||||
|
@ -222,13 +220,15 @@ mouseclose(Chan *c)
|
|||
unlock(&mouse);
|
||||
return;
|
||||
}
|
||||
if(--mouse.ref == 0){
|
||||
cursoroff(1);
|
||||
curs = arrow;
|
||||
Cursortocursor(&arrow);
|
||||
cursoron(1);
|
||||
if(--mouse.ref != 0){
|
||||
unlock(&mouse);
|
||||
return;
|
||||
}
|
||||
unlock(&mouse);
|
||||
cursoroff();
|
||||
curs = arrow;
|
||||
Cursortocursor(&arrow);
|
||||
cursoron();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,7 +373,7 @@ mousewrite(Chan *c, void *va, long n, vlong)
|
|||
error(Eisdir);
|
||||
|
||||
case Qcursor:
|
||||
cursoroff(1);
|
||||
cursoroff();
|
||||
if(n < 2*4+2*2*16){
|
||||
curs = arrow;
|
||||
Cursortocursor(&arrow);
|
||||
|
@ -385,11 +385,7 @@ mousewrite(Chan *c, void *va, long n, vlong)
|
|||
memmove(curs.set, p+40, 2*16);
|
||||
Cursortocursor(&curs);
|
||||
}
|
||||
qlock(&mouse);
|
||||
mouse.redraw = 1;
|
||||
mouseclock();
|
||||
qunlock(&mouse);
|
||||
cursoron(1);
|
||||
cursoron();
|
||||
return n;
|
||||
|
||||
case Qmousectl:
|
||||
|
@ -466,14 +462,10 @@ mousewrite(Chan *c, void *va, long n, vlong)
|
|||
if(p == 0)
|
||||
error(Eshort);
|
||||
pt.y = strtoul(p, 0, 0);
|
||||
qlock(&mouse);
|
||||
if(ptinrect(pt, gscreen->r)){
|
||||
if(gscreen != nil && ptinrect(pt, gscreen->r)){
|
||||
mouse.xy = pt;
|
||||
mouse.redraw = 1;
|
||||
mouse.track = 1;
|
||||
mouseclock();
|
||||
mousetrack(0, 0, mouse.buttons, TK2MS(MACHP(0)->ticks));
|
||||
}
|
||||
qunlock(&mouse);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -505,32 +497,40 @@ Dev mousedevtab = {
|
|||
void
|
||||
Cursortocursor(Cursor *c)
|
||||
{
|
||||
qlock(&drawlock);
|
||||
lock(&cursor);
|
||||
memmove(&cursor.Cursor, c, sizeof(Cursor));
|
||||
setcursor(c);
|
||||
unlock(&cursor);
|
||||
qunlock(&drawlock);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
shouldredraw(void*)
|
||||
{
|
||||
return mouse.redraw != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* called by the clock routine to redraw the cursor
|
||||
* process that redraws the cursor
|
||||
*/
|
||||
static void
|
||||
mouseclock(void)
|
||||
mouseproc(void*)
|
||||
{
|
||||
if(mouse.track){
|
||||
mousetrack(mouse.dx, mouse.dy, mouse.buttons, TK2MS(MACHP(0)->ticks));
|
||||
mouse.track = 0;
|
||||
mouse.dx = 0;
|
||||
mouse.dy = 0;
|
||||
while(waserror())
|
||||
;
|
||||
for(;;){
|
||||
if(mouse.redraw){
|
||||
mouse.redraw = 0;
|
||||
cursoroff();
|
||||
cursoron();
|
||||
drawactive(1);
|
||||
} else {
|
||||
drawactive(0);
|
||||
}
|
||||
tsleep(&mouse.redrawr, shouldredraw, 0, 20*1000);
|
||||
}
|
||||
if(mouse.redraw && canlock(&cursor)){
|
||||
mouse.redraw = 0;
|
||||
cursoroff(0);
|
||||
mouse.redraw = cursoron(0);
|
||||
unlock(&cursor);
|
||||
}
|
||||
drawactive(0);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -595,7 +595,6 @@ absmousetrack(int x, int y, int b, int msec)
|
|||
lastb = mouse.buttons;
|
||||
mouse.xy = Pt(x, y);
|
||||
mouse.buttons = b;
|
||||
mouse.redraw = 1;
|
||||
mouse.counter++;
|
||||
mouse.msec = msec;
|
||||
|
||||
|
@ -611,7 +610,8 @@ absmousetrack(int x, int y, int b, int msec)
|
|||
mouse.qfull = 1;
|
||||
}
|
||||
wakeup(&mouse.r);
|
||||
drawactive(1);
|
||||
|
||||
mouseredraw();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -782,3 +782,9 @@ mouseresize(void)
|
|||
wakeup(&mouse.r);
|
||||
}
|
||||
|
||||
void
|
||||
mouseredraw(void)
|
||||
{
|
||||
mouse.redraw = 1;
|
||||
wakeup(&mouse.redrawr);
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ devuart.$O: ../port/netif.h
|
|||
devmouse.$O: screen.h /sys/include/memdraw.h
|
||||
devdraw.$O: screen.h /sys/include/memdraw.h
|
||||
screen.$O: screen.h /sys/include/memdraw.h
|
||||
swcursor.$O: screen.h /sys/include/memdraw.h
|
||||
thwack.$O: ../port/thwack.h
|
||||
unthwack.$O: ../port/thwack.h
|
||||
devsdp.$O: ../port/thwack.h
|
||||
|
|
133
sys/src/9/port/swcursor.c
Normal file
133
sys/src/9/port/swcursor.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "../port/error.h"
|
||||
|
||||
#define Image IMAGE
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <cursor.h>
|
||||
#include "screen.h"
|
||||
|
||||
extern Memimage* gscreen;
|
||||
|
||||
/*
|
||||
* Software cursor.
|
||||
*/
|
||||
static Memimage* swback; /* screen under cursor */
|
||||
static Memimage* swimg; /* cursor image */
|
||||
static Memimage* swmask; /* cursor mask */
|
||||
static Memimage* swimg1;
|
||||
static Memimage* swmask1;
|
||||
|
||||
static Point swoffset;
|
||||
static Rectangle swrect; /* screen rectangle in swback */
|
||||
static Point swvispt; /* actual cursor location */
|
||||
static int swvisible; /* is the cursor visible? */
|
||||
|
||||
/*
|
||||
* called with drawlock locked for us, most of the time.
|
||||
* kernel prints at inopportune times might mean we don't
|
||||
* hold the lock, but memimagedraw is now reentrant so
|
||||
* that should be okay: worst case we get cursor droppings.
|
||||
*/
|
||||
void
|
||||
swcursorhide(void)
|
||||
{
|
||||
if(swvisible == 0)
|
||||
return;
|
||||
if(swback == nil || gscreen == nil)
|
||||
return;
|
||||
swvisible = 0;
|
||||
memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
|
||||
flushmemscreen(swrect);
|
||||
}
|
||||
|
||||
void
|
||||
swcursoravoid(Rectangle r)
|
||||
{
|
||||
if(swvisible && rectXrect(r, swrect)){
|
||||
swcursorhide();
|
||||
mouseredraw(); /* schedule cursor redraw after we release drawlock */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
swcursordraw(Point p)
|
||||
{
|
||||
if(swvisible)
|
||||
return;
|
||||
if(swback == nil || swimg1 == nil || swmask1 == nil || gscreen == nil)
|
||||
return;
|
||||
assert(!canqlock(&drawlock));
|
||||
swvispt = addpt(swoffset, p);
|
||||
swrect = rectaddpt(Rect(0,0,16,16), swvispt);
|
||||
memimagedraw(swback, swback->r, gscreen, swvispt, memopaque, ZP, S);
|
||||
memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
|
||||
flushmemscreen(swrect);
|
||||
swvisible = 1;
|
||||
}
|
||||
|
||||
void
|
||||
swcursorload(Cursor *curs)
|
||||
{
|
||||
uchar *ip, *mp;
|
||||
int i, j, set, clr;
|
||||
|
||||
if(swimg == nil || swmask == nil || swimg1 == nil || swmask1 == nil)
|
||||
return;
|
||||
/*
|
||||
* Build cursor image and mask.
|
||||
* Image is just the usual cursor image
|
||||
* but mask is a transparent alpha mask.
|
||||
*
|
||||
* The 16x16x8 memimages do not have
|
||||
* padding at the end of their scan lines.
|
||||
*/
|
||||
ip = byteaddr(swimg, ZP);
|
||||
mp = byteaddr(swmask, ZP);
|
||||
for(i=0; i<32; i++){
|
||||
set = curs->set[i];
|
||||
clr = curs->clr[i];
|
||||
for(j=0x80; j; j>>=1){
|
||||
*ip++ = set&j ? 0x00 : 0xFF;
|
||||
*mp++ = (clr|set)&j ? 0xFF : 0x00;
|
||||
}
|
||||
}
|
||||
swoffset = curs->offset;
|
||||
memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
|
||||
memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
|
||||
|
||||
mouseredraw();
|
||||
}
|
||||
|
||||
void
|
||||
swcursorinit(void)
|
||||
{
|
||||
if(gscreen == nil)
|
||||
return;
|
||||
|
||||
if(swback){
|
||||
freememimage(swback);
|
||||
freememimage(swmask);
|
||||
freememimage(swmask1);
|
||||
freememimage(swimg);
|
||||
freememimage(swimg1);
|
||||
}
|
||||
swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
|
||||
swmask = allocmemimage(Rect(0,0,16,16), GREY8);
|
||||
swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
||||
swimg = allocmemimage(Rect(0,0,16,16), GREY8);
|
||||
swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
|
||||
if(swback == nil || swmask == nil || swmask1 == nil || swimg == nil || swimg1 == nil){
|
||||
print("software cursor: allocmemimage fails\n");
|
||||
return;
|
||||
}
|
||||
memfillcolor(swback, DTransparent);
|
||||
memfillcolor(swmask, DOpaque);
|
||||
memfillcolor(swmask1, DOpaque);
|
||||
memfillcolor(swimg, DBlack);
|
||||
memfillcolor(swimg1, DBlack);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue