
making sure to close the dot in every kproc appears repetitive, so instead stop inheriting the dot in kproc() as this is usually never what you wanted in the first place.
345 lines
5.6 KiB
C
345 lines
5.6 KiB
C
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "io.h"
|
|
#include "../port/error.h"
|
|
|
|
#define Image IMAGE
|
|
#include <draw.h>
|
|
#include <memdraw.h>
|
|
#include <cursor.h>
|
|
#include "screen.h"
|
|
|
|
Memimage *gscreen;
|
|
|
|
static struct {
|
|
Rendez;
|
|
|
|
Rectangle rect;
|
|
Proc *proc;
|
|
|
|
uintptr addr;
|
|
} fbscreen;
|
|
|
|
static struct {
|
|
Rendez;
|
|
|
|
Cursor;
|
|
|
|
Proc *proc;
|
|
uintptr addr;
|
|
} hwcursor;
|
|
|
|
void
|
|
cursoron(void)
|
|
{
|
|
wakeup(&hwcursor);
|
|
}
|
|
|
|
void
|
|
cursoroff(void)
|
|
{
|
|
}
|
|
|
|
void
|
|
setcursor(Cursor *curs)
|
|
{
|
|
hwcursor.Cursor = *curs;
|
|
}
|
|
|
|
void
|
|
flushmemscreen(Rectangle r)
|
|
{
|
|
if(badrect(fbscreen.rect))
|
|
fbscreen.rect = r;
|
|
else
|
|
combinerect(&fbscreen.rect, r);
|
|
wakeup(&fbscreen);
|
|
}
|
|
|
|
void
|
|
screeninit(void)
|
|
{
|
|
conf.monitor = 1;
|
|
}
|
|
|
|
uchar*
|
|
attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
|
|
{
|
|
if(gscreen == nil)
|
|
return nil;
|
|
|
|
*r = gscreen->r;
|
|
*d = gscreen->depth;
|
|
*chan = gscreen->chan;
|
|
*width = gscreen->width;
|
|
|
|
/* make devdraw use gscreen->data */
|
|
*softscreen = 0xa110c;
|
|
gscreen->data->ref++;
|
|
|
|
return gscreen->data->bdata;
|
|
}
|
|
|
|
void
|
|
getcolor(ulong, ulong *, ulong *, ulong *)
|
|
{
|
|
}
|
|
|
|
int
|
|
setcolor(ulong, ulong, ulong, ulong)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
blankscreen(int)
|
|
{
|
|
}
|
|
|
|
|
|
static void
|
|
cursorproc(void *arg)
|
|
{
|
|
uchar *set, *clr;
|
|
u32int *reg;
|
|
Point xy;
|
|
int i;
|
|
|
|
for(i = 0; i < NSEG; i++)
|
|
if(up->seg[i] == nil && i != ESEG)
|
|
break;
|
|
if(i == NSEG)
|
|
panic(up->text);
|
|
|
|
up->seg[i] = arg;
|
|
|
|
hwcursor.proc = up;
|
|
if(waserror()){
|
|
hwcursor.addr = 0;
|
|
hwcursor.proc = nil;
|
|
pexit("detached", 1);
|
|
}
|
|
|
|
reg = (u32int*)hwcursor.addr;
|
|
for(;;){
|
|
eqlock(&drawlock);
|
|
xy = addpt(mousexy(), hwcursor.offset);
|
|
qunlock(&drawlock);
|
|
|
|
set = hwcursor.set;
|
|
clr = hwcursor.clr;
|
|
for(i=0; i<8; i++){
|
|
reg[0x70/4 + i] = clr[i*4]<<24 | clr[i*4+1]<<16 | clr[i*4+2]<<8 | clr[i*4+3];
|
|
reg[0x90/4 + i] = set[i*4]<<24 | set[i*4+1]<<16 | set[i*4+2]<<8 | set[i*4+3];
|
|
}
|
|
reg[0] = (xy.x<<16) | (xy.y&0xFFFF);
|
|
|
|
sleep(&hwcursor, return0, nil);
|
|
}
|
|
}
|
|
|
|
void
|
|
mousectl(Cmdbuf *cb)
|
|
{
|
|
Segment *s;
|
|
uintptr addr;
|
|
|
|
if(strcmp(cb->f[0], "addr") == 0 && cb->nf == 2){
|
|
s = nil;
|
|
addr = strtoul(cb->f[1], 0, 0);
|
|
if(addr != 0){
|
|
if((s = seg(up, addr, 0)) == nil || (s->type&SG_RONLY) != 0
|
|
|| (addr&3) != 0 || addr+0xB0 > s->top)
|
|
error(Ebadarg);
|
|
incref(s);
|
|
}
|
|
if(hwcursor.proc != nil){
|
|
postnote(hwcursor.proc, 0, "die", NUser);
|
|
while(hwcursor.proc != nil)
|
|
sched();
|
|
}
|
|
if(addr != 0){
|
|
hwcursor.addr = addr;
|
|
kproc("cursor", cursorproc, s);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if(strcmp(cb->f[0], "linear") == 0){
|
|
mouseaccelerate(0);
|
|
return;
|
|
}
|
|
|
|
if(strcmp(cb->f[0], "accelerated") == 0){
|
|
mouseaccelerate(cb->nf == 1 ? 1 : atoi(cb->f[1]));
|
|
return;
|
|
}
|
|
}
|
|
|
|
static int
|
|
isflush(void *)
|
|
{
|
|
return !badrect(fbscreen.rect);
|
|
}
|
|
|
|
static void
|
|
screenproc(void *arg)
|
|
{
|
|
int sno, n, w;
|
|
uchar *sp, *dp, *top;
|
|
Rectangle r;
|
|
|
|
for(sno = 0; sno < NSEG; sno++)
|
|
if(up->seg[sno] == nil && sno != ESEG)
|
|
break;
|
|
if(sno == NSEG)
|
|
panic(up->text);
|
|
|
|
up->seg[sno] = arg;
|
|
|
|
fbscreen.proc = up;
|
|
if(waserror()){
|
|
fbscreen.addr = 0;
|
|
fbscreen.proc = nil;
|
|
pexit("detached", 1);
|
|
}
|
|
|
|
for(;;){
|
|
sleep(&fbscreen, isflush, nil);
|
|
|
|
eqlock(&drawlock);
|
|
r = fbscreen.rect;
|
|
fbscreen.rect = ZR;
|
|
if(badrect(r) || gscreen == nil || rectclip(&r, gscreen->r) == 0){
|
|
qunlock(&drawlock);
|
|
continue;
|
|
}
|
|
w = sizeof(ulong)*gscreen->width;
|
|
n = bytesperline(r, gscreen->depth);
|
|
sp = byteaddr(gscreen, r.min);
|
|
dp = (uchar*)fbscreen.addr + (sp - &gscreen->data->bdata[gscreen->zero]);
|
|
top = (uchar*)up->seg[sno]->top;
|
|
if(dp+(Dy(r)-1)*w+n > top)
|
|
r.max.y = (top-(uchar*)fbscreen.addr)/w;
|
|
qunlock(&drawlock);
|
|
|
|
while(r.min.y < r.max.y) {
|
|
memmove(dp, sp, n);
|
|
sp += w;
|
|
dp += w;
|
|
r.min.y++;
|
|
}
|
|
}
|
|
}
|
|
|
|
enum {
|
|
CMaddr,
|
|
CMsize,
|
|
CMinit,
|
|
};
|
|
|
|
static Cmdtab fbctlmsg[] = {
|
|
CMaddr, "addr", 2,
|
|
CMsize, "size", 3,
|
|
CMinit, "init", 1,
|
|
};
|
|
|
|
long
|
|
fbctlwrite(Chan*, void *a, long n, vlong)
|
|
{
|
|
Cmdbuf *cb;
|
|
Cmdtab *ct;
|
|
ulong x, y, z, chan;
|
|
Segment *s;
|
|
uintptr addr;
|
|
char *p;
|
|
|
|
cb = parsecmd(a, n);
|
|
if(waserror()){
|
|
free(cb);
|
|
nexterror();
|
|
}
|
|
ct = lookupcmd(cb, fbctlmsg, nelem(fbctlmsg));
|
|
switch(ct->index){
|
|
case CMaddr:
|
|
s = nil;
|
|
addr = strtoul(cb->f[1], 0, 0);
|
|
if(addr != 0){
|
|
if((s = seg(up, addr, 0)) == nil || (s->type&SG_RONLY) != 0)
|
|
error(Ebadarg);
|
|
incref(s);
|
|
}
|
|
if(fbscreen.proc != nil){
|
|
postnote(fbscreen.proc, 0, "die", NUser);
|
|
while(fbscreen.proc != nil)
|
|
sched();
|
|
}
|
|
if(addr != 0){
|
|
fbscreen.addr = addr;
|
|
kproc("screen", screenproc, s);
|
|
}
|
|
break;
|
|
|
|
case CMsize:
|
|
x = strtoul(cb->f[1], &p, 0);
|
|
if(x == 0 || x > 10240)
|
|
error(Ebadarg);
|
|
if(*p)
|
|
p++;
|
|
y = strtoul(p, &p, 0);
|
|
if(y == 0 || y > 10240)
|
|
error(Ebadarg);
|
|
if(*p)
|
|
p++;
|
|
z = strtoul(p, &p, 0);
|
|
|
|
if((chan = strtochan(cb->f[2])) == 0)
|
|
error("bad channel");
|
|
if(chantodepth(chan) != z)
|
|
error("depth, channel do not match");
|
|
|
|
deletescreenimage();
|
|
eqlock(&drawlock);
|
|
if(memimageinit() < 0){
|
|
qunlock(&drawlock);
|
|
error("memimageinit failed");
|
|
}
|
|
if(gscreen != nil){
|
|
freememimage(gscreen);
|
|
gscreen = nil;
|
|
}
|
|
gscreen = allocmemimage(Rect(0,0,x,y), chan);
|
|
qunlock(&drawlock);
|
|
/* wet floor */
|
|
|
|
case CMinit:
|
|
if(gscreen == nil)
|
|
error("no framebuffer");
|
|
resetscreenimage();
|
|
break;
|
|
}
|
|
free(cb);
|
|
poperror();
|
|
return n;
|
|
}
|
|
|
|
long
|
|
fbctlread(Chan*, void *a, long n, vlong offset)
|
|
{
|
|
char buf[256], chan[32], *p, *e;
|
|
|
|
p = buf;
|
|
e = p + sizeof(buf);
|
|
qlock(&drawlock);
|
|
if(gscreen != nil){
|
|
p = seprint(p, e, "size %dx%dx%d %s\n",
|
|
Dx(gscreen->r), Dy(gscreen->r), gscreen->depth,
|
|
chantostr(chan, gscreen->chan));
|
|
}
|
|
qunlock(&drawlock);
|
|
seprint(p, e, "addr %#p\n", fbscreen.addr);
|
|
return readstr(offset, a, n, buf);
|
|
}
|