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