summaryrefslogtreecommitdiff
path: root/os/port/swcursor.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/port/swcursor.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/port/swcursor.c')
-rw-r--r--os/port/swcursor.c358
1 files changed, 358 insertions, 0 deletions
diff --git a/os/port/swcursor.c b/os/port/swcursor.c
new file mode 100644
index 00000000..b4e2628c
--- /dev/null
+++ b/os/port/swcursor.c
@@ -0,0 +1,358 @@
+#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);
+}