xref: /inferno-os/os/sa1110/softcursor.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 #include "io.h"
8 
9 #include <draw.h>
10 #include <memdraw.h>
11 #include <cursor.h>
12 
13 #include "gscreen.h"
14 
15 /*
16  * Software cursor code: done by hand, might be better to use memimagedraw
17  * but that would need to be done by a process
18  */
19 
20 typedef struct Cursordata Cursordata;
21 struct Cursordata {
22 	Physdisplay	*vd;
23 	ulong	*fb;	/* screen frame buffer */
24 	Rectangle r;
25 	int	depth;	/* depth of screen */
26 	int 	width;	/* width of screen in ulongs */
27 	int	x;
28 	int	y;
29 	int	hotx;
30 	int	hoty;
31 	int	cbwid;	/* cursor byte width */
32 	int	f;	/* flags */
33 	int	dx;
34 	int	dy;
35 	int	hidecount;
36 	uchar	data[CURSWID*CURSHGT];
37 	uchar	mask[CURSWID*CURSHGT];
38 	uchar	save[CURSWID*CURSHGT];
39 };
40 
41 static Cursordata *cd = nil;
42 
43 enum {
44 	Enabled = 0x01,		/* cursor is enabled */
45 	Drawn = 0x02,		/* cursor is currently drawn */
46 	Bitswap = 0x10,
47 };
48 
49 static Rectangle cursoroffrect;
50 static int	cursorisoff;
51 
52 static void swcursorflush(Point);
53 static void	swcurs_draw_or_undraw(Cursordata *);
54 
55 static void
cursorupdate0(void)56 cursorupdate0(void)
57 {
58 	int inrect, x, y;
59 	Point m;
60 
61 	m = mousexy();
62 	x = m.x - cd->hotx;
63 	y = m.y - cd->hoty;
64 	inrect = (x >= cursoroffrect.min.x && x < cursoroffrect.max.x
65 		&& y >= cursoroffrect.min.y && y < cursoroffrect.max.y);
66 	if (cursorisoff == inrect)
67 		return;
68 	cursorisoff = inrect;
69 	if (inrect)
70 		swcurs_hide(swc);
71 	else {
72 		cd->hidecount = 0;
73 		swcurs_draw_or_undraw(swc);
74 	}
75 	swcursorflush(m);
76 }
77 
78 void
cursorupdate(Rectangle r)79 cursorupdate(Rectangle r)
80 {
81 	lock(vd);
82 	r.min.x -= 16;
83 	r.min.y -= 16;
84 	cursoroffrect = r;
85 	if (vd->cursor != nil)
86 		cursorupdate0();
87 	unlock(vd);
88 }
89 
90 void
cursorenable(void)91 cursorenable(void)
92 {
93 	lock(vd);
94 	if(vd->cursor != nil)
95 		vd->cursor->enable(swc);
96 //		swcursorflush(mousexy());
97 	unlock(vd);
98 }
99 
100 void
cursordisable(void)101 cursordisable(void)
102 {
103 
104 	lock(vd);
105 	if(swc != nil) {
106 		swcurs_disable(swc);
107 		swcursorflush(mousexy());
108 	}
109 	unlock(vd);
110 }
111 
112 static void
swcursupdate(int oldx,int oldy,int x,int y)113 swcursupdate(int oldx, int oldy, int x, int y)
114 {
115 
116 	if(!canlock(vd))
117 		return;		/* if can't lock, don't wake up stuff */
118 
119 	if(x < gscreen->r.min.x)
120 		x = gscreen->r.min.x;
121 	if(x >= gscreen->r.max.x)
122 		x = gscreen->r.max.x;
123 	if(y < gscreen->r.min.y)
124 		y = gscreen->r.min.y;
125 	if(y >= gscreen->r.max.y)
126 		y = gscreen->r.max.y;
127 	if(swc != nil) {
128 		swcurs_hide(swc);
129 		cd->x = x;
130 		cd->y = y;
131 		cursorupdate0();
132 		swcurs_unhide(swc);
133 		swcursorflush(oldx, oldy);
134 		swcursorflush(x, y);
135 	}
136 
137 	unlock(vd);
138 }
139 
140 void
drawcursor(Drawcursor * c)141 drawcursor(Drawcursor* c)
142 {
143 	Point p;
144 	Cursor curs, *cp;
145 	int j, i, h, bpl;
146 	uchar *bc, *bs, *cclr, *cset;
147 
148 	if(swc == nil)
149 		return;
150 
151 	/* Set the default system cursor */
152 	if(c == nil || c->data == nil){
153 		swcurs_disable(swc);
154 		return;
155 	}
156 	else {
157 		cp = &curs;
158 		p.x = c->hotx;
159 		p.y = c->hoty;
160 		cp->offset = p;
161 		bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 1);
162 
163 		h = (c->maxy-c->miny)/2;
164 		if(h > 16)
165 			h = 16;
166 
167 		bc = c->data;
168 		bs = c->data + h*bpl;
169 
170 		cclr = cp->clr;
171 		cset = cp->set;
172 		for(i = 0; i < h; i++) {
173 			for(j = 0; j < 2; j++) {
174 				cclr[j] = bc[j];
175 				cset[j] = bs[j];
176 			}
177 			bc += bpl;
178 			bs += bpl;
179 			cclr += 2;
180 			cset += 2;
181 		}
182 	}
183 	swcurs_load(swc, cp);
184 	swcursorflush(mousexy());
185 	swcurs_enable(swc);
186 }
187 
188 void*
create(Physdisplay * vd)189 create(Physdisplay *vd)
190 {
191 	Cursordata *cd;
192 
193 	swc = (Cursordata*)malloc(sizeof(Cursordata));
194 	cd->vd = vd;
195 	cd->fb = vd->gscreen->data->bdata;	/* or vd->fb? */
196 	cd->r = vd->gscreen->r;
197 	cd->d = vd->gscreen->depth;
198 	cd->width = vd->gscreen->width;
199 //	cd->f = bitswap ? Bitswap : 0;
200 	cd->f = Bitswap;	/* ??? */
201 	cd->x = cd->y = 0;
202 	cd->hotx = cd->hoty = 0;
203 	cd->hidecount = 0;
204 	return cd;
205 }
206 
207 void
swcurs_destroy(Cursordata * cd)208 swcurs_destroy(Cursordata *cd)
209 {
210 	swcurs_disable(cd);
211 	free(cd);
212 }
213 
214 static void
swcursorflush(Point p)215 swcursorflush(Point p)
216 {
217 	Rectangle r;
218 
219 	/* XXX a little too paranoid here */
220 	r.min.x = p.x-16;
221 	r.min.y = p.y-16;
222 	r.max.x = p.x+17;
223 	r.max.y = p.y+17;
224 	flushmemscreen(r);
225 }
226 
227 static void
swcurs_draw_or_undraw(Cursordata * cd)228 swcurs_draw_or_undraw(Cursordata *cd)
229 {
230 	uchar *p;
231 	uchar *cs;
232 	int w, vw;
233 	int x1 = cd->r.min.x;
234 	int y1 = cd->r.min.y;
235 	int x2 = cd->r.max.x;
236 	int y2 = cd->r.max.y;
237 	int xp = cd->x - cd->hotx;
238 	int yp = cd->y - cd->hoty;
239 	int ofs;
240 
241 	if(((cd->f & Enabled) && (cd->hidecount <= 0))
242 			 == ((cd->f & Drawn) != 0))
243 		return;
244 	w = cd->cbwid*BI2BY/cd->depth;
245 	x1 = xp < x1 ? x1 : xp;
246 	y1 = yp < y1 ? y1 : yp;
247 	x2 = xp+w >= x2 ? x2 : xp+w;
248 	y2 = yp+cd->dy >= y2 ? y2 : yp+cd->dy;
249 	if(x2 <= x1 || y2 <= y1)
250 		return;
251 	p = (uchar*)(cd->fb + cd->width*y1) + x1*(1 << cd->d)/BI2BY;
252 	y2 -= y1;
253 	x2 = (x2-x1)*cd->depth/BI2BY;
254 	vw = cd->width*BY2WD - x2;
255 	w = cd->cbwid - x2;
256 	ofs = cd->cbwid*(y1-yp)+(x1-xp);
257 	cs = cd->save + ofs;
258 	if((cd->f ^= Drawn) & Drawn) {
259 		uchar *cm = cd->mask + ofs;
260 		uchar *cd = cd->data + ofs;
261 		while(y2--) {
262 			x1 = x2;
263 			while(x1--) {
264 				*cs++ = *p;
265 				*p = (*p & *cm++) ^ *cd++;
266 				p++;
267 			}
268 			cs += w;
269 			cm += w;
270 			cd += w;
271 			p += vw;
272 		}
273 	} else {
274 		while(--y2 >= 0){
275 			for(x1 = x2; --x1 >= 0;)
276 				*p++ = *cs++;
277 			cs += w;
278 			p += vw;
279 		}
280 	}
281 }
282 
283 static void
swcurs_hide(Cursordata * cd)284 swcurs_hide(Cursordata *cd)
285 {
286 	++cd->hidecount;
287 	swcurs_draw_or_undraw(swc);
288 }
289 
290 static void
swcurs_unhide(Cursordata * cd)291 swcurs_unhide(Cursordata *cd)
292 {
293 	if (--cd->hidecount < 0)
294 		cd->hidecount = 0;
295 	swcurs_draw_or_undraw(swc);
296 }
297 
298 static void
swcurs_enable(Cursordata * cd)299 swcurs_enable(Cursordata *cd)
300 {
301 	cd->f |= Enabled;
302 	swcurs_draw_or_undraw(swc);
303 }
304 
305 void
swcurs_disable(Cursordata * cd)306 swcurs_disable(Cursordata *cd)
307 {
308 	cd->f &= ~Enabled;
309 	swcurs_draw_or_undraw(swc);
310 }
311 
312 static void
load(Cursordata * cd,Cursor * c)313 load(Cursordata *cd, Cursor *c)
314 {
315 	int i, k;
316 	uchar *bc, *bs, *cd, *cm;
317 	static uchar bdv[4] = {0,Backgnd,Foregnd,0xff};
318 	static uchar bmv[4] = {0xff,0,0,0xff};
319 	int bits = 1<<cd->depth;
320 	uchar mask = (1<<bits)-1;
321 	int bswp = (cd->f&Bitswap) ? 8-bits : 0;
322 
323 	bc = c->clr;
324 	bs = c->set;
325 
326 	swcurs_hide(swc);
327 	cd = cd->data;
328 	cm = cd->mask;
329 	cd->hotx = c->offset.x;
330 	cd->hoty = c->offset.y;
331 	cd->dy = CURSHGT;
332 	cd->dx = CURSWID;
333 	cd->cbwid = CURSWID*(1<<cd->d)/BI2BY;
334 	for(i = 0; i < CURSWID/BI2BY*CURSHGT; i++) {
335 		uchar bcb = *bc++;
336 		uchar bsb = *bs++;
337 		for(k=0; k<BI2BY;) {
338 			uchar cdv = 0;
339 			uchar cmv = 0;
340 			int z;
341 			for(z=0; z<BI2BY; z += bits) {
342 				int n = ((bsb&(0x80))|((bcb&(0x80))<<1))>>7;
343 				int s = z^bswp;
344 				cdv |= (bdv[n]&mask) << s;
345 				cmv |= (bmv[n]&mask) << s;
346 				bcb <<= 1;
347 				bsb <<= 1;
348 				k++;
349 			}
350 			*cd++ = cdv;
351 			*cm++ = cmv;
352 		}
353 	}
354 	swcurs_unhide(swc);
355 }
356 
357 Physcursor softcursor = {
358 	.name = "softcursor",
359 	.create = create,
360 	.enable = swenable,
361 	.disable = swdisable,
362 	.load = load,
363 	.move = move,
364 	.destroy = destroy,
365 };
366