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