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