screen.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  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. #include <draw.h>
  9. #include <memdraw.h>
  10. #include <cursor.h>
  11. #include "screen.h"
  12. enum {
  13. Backgnd = 0xFF, /* white */
  14. Foregnd = 0x00, /* black */
  15. };
  16. #define DPRINT if(1)iprint
  17. static Memdata xgdata;
  18. static Memimage xgscreen =
  19. {
  20. {0, 0, 0, 0}, /* r */
  21. {0, 0, 0, 0}, /* clipr */
  22. 8, /* depth */
  23. 1, /* nchan */
  24. CMAP8, /* chan */
  25. nil, /* cmap */
  26. &xgdata, /* data */
  27. 0, /* zero */
  28. 0, /* width */
  29. nil, /* layer */
  30. 0, /* flags */
  31. };
  32. Memimage *gscreen;
  33. Memimage *conscol;
  34. Memimage *back;
  35. Memsubfont *memdefont;
  36. static Point curpos;
  37. static Rectangle window;
  38. typedef struct SWcursor SWcursor;
  39. static Vdisplay *vd;
  40. static SWcursor *swc = nil;
  41. SWcursor* swcurs_create(ulong *, int, int, Rectangle, int);
  42. void swcurs_destroy(SWcursor*);
  43. void swcurs_enable(SWcursor*);
  44. void swcurs_disable(SWcursor*);
  45. void swcurs_hide(SWcursor*);
  46. void swcurs_unhide(SWcursor*);
  47. void swcurs_load(SWcursor*, Cursor*);
  48. void swcursupdate(int, int, int, int);
  49. static char printbuf[1024];
  50. static int printbufpos = 0;
  51. static void lcdscreenputs(char*, int);
  52. static void screenpbuf(char*, int);
  53. void (*screenputs)(char*, int) = screenpbuf;
  54. static Cursor arrow = {
  55. { -1, -1 },
  56. { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
  57. 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
  58. 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
  59. 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
  60. },
  61. { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
  62. 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
  63. 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
  64. 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
  65. },
  66. };
  67. static ushort palette16[256];
  68. static void (*flushpixels)(Rectangle, ulong*, int, ulong*, int);
  69. static void flush8to4(Rectangle, ulong*, int, ulong*, int);
  70. static void flush8to4r(Rectangle, ulong*, int, ulong*, int);
  71. static void flush8to16(Rectangle, ulong*, int, ulong*, int);
  72. static void flush8to16r(Rectangle, ulong*, int, ulong*, int);
  73. /*
  74. lccr0=000000b9 lccr1=0b100930 lccr2=0a0108ef lccr3=00300010
  75. ---
  76. vd->wid=320 bwid=640 gscreen->width=60 fb=d0b7cb80 data=d0ba25c0
  77. */
  78. int
  79. setcolor(ulong p, ulong r, ulong g, ulong b)
  80. {
  81. if(vd->depth >= 8)
  82. p &= 0xff;
  83. else
  84. p &= 0xf;
  85. vd->colormap[p][0] = r;
  86. vd->colormap[p][1] = g;
  87. vd->colormap[p][2] = b;
  88. palette16[p] = ((r>>(32-4))<<12)|((g>>(32-4))<<7)|((b>>(32-4))<<1);
  89. lcd_setcolor(p, r, g, b);
  90. return ~0;
  91. }
  92. void
  93. getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
  94. {
  95. if(vd->depth >= 8)
  96. p = (p&0xff)^0xff;
  97. else
  98. p = (p&0xf)^0xf;
  99. *pr = vd->colormap[p][0];
  100. *pg = vd->colormap[p][1];
  101. *pb = vd->colormap[p][2];
  102. }
  103. void
  104. graphicscmap(int invert)
  105. {
  106. int num, den, i, j;
  107. int r, g, b, cr, cg, cb, v, p;
  108. for(r=0,i=0;r!=4;r++) for(v=0;v!=4;v++,i+=16){
  109. for(g=0,j=v-r;g!=4;g++) for(b=0;b!=4;b++,j++){
  110. den=r;
  111. if(g>den) den=g;
  112. if(b>den) den=b;
  113. if(den==0) /* divide check -- pick grey shades */
  114. cr=cg=cb=v*17;
  115. else{
  116. num=17*(4*den+v);
  117. cr=r*num/den;
  118. cg=g*num/den;
  119. cb=b*num/den;
  120. }
  121. p = (i+(j&15));
  122. if(invert)
  123. p ^= 0xFF;
  124. if(vd->depth == 4) {
  125. if((p&0xf) != (p>>4))
  126. continue;
  127. p &= 0xf;
  128. }
  129. setcolor(p,
  130. cr*0x01010101,
  131. cg*0x01010101,
  132. cb*0x01010101);
  133. }
  134. }
  135. lcd_flush();
  136. }
  137. static uchar lum[256]={
  138. 0, 7, 15, 23, 39, 47, 55, 63, 79, 87, 95, 103, 119, 127, 135, 143,
  139. 154, 17, 9, 17, 25, 49, 59, 62, 68, 89, 98, 107, 111, 129, 138, 146,
  140. 157, 166, 34, 11, 19, 27, 59, 71, 69, 73, 99, 109, 119, 119, 139, 148,
  141. 159, 169, 178, 51, 13, 21, 29, 69, 83, 75, 78, 109, 120, 131, 128, 149,
  142. 28, 35, 43, 60, 68, 75, 83, 100, 107, 115, 123, 140, 147, 155, 163, 20,
  143. 25, 35, 40, 47, 75, 85, 84, 89, 112, 121, 129, 133, 151, 159, 168, 176,
  144. 190, 30, 42, 44, 50, 90, 102, 94, 97, 125, 134, 144, 143, 163, 172, 181,
  145. 194, 204, 35, 49, 49, 54, 105, 119, 103, 104, 137, 148, 158, 154, 175, 184,
  146. 56, 63, 80, 88, 96, 103, 120, 128, 136, 143, 160, 168, 175, 183, 40, 48,
  147. 54, 63, 69, 90, 99, 107, 111, 135, 144, 153, 155, 173, 182, 190, 198, 45,
  148. 50, 60, 70, 74, 100, 110, 120, 120, 150, 160, 170, 167, 186, 195, 204, 214,
  149. 229, 55, 66, 77, 79, 110, 121, 131, 129, 165, 176, 187, 179, 200, 210, 219,
  150. 84, 100, 108, 116, 124, 140, 148, 156, 164, 180, 188, 196, 204, 60, 68, 76,
  151. 82, 91, 108, 117, 125, 134, 152, 160, 169, 177, 195, 204, 212, 221, 66, 74,
  152. 80, 89, 98, 117, 126, 135, 144, 163, 172, 181, 191, 210, 219, 228, 238, 71,
  153. 76, 85, 95, 105, 126, 135, 145, 155, 176, 185, 195, 205, 225, 235, 245, 255,
  154. };
  155. void flushmemscreen(Rectangle r);
  156. void
  157. screenclear(void)
  158. {
  159. memimagedraw(gscreen, gscreen->r, memwhite, ZP, memopaque, ZP, SoverD);
  160. curpos = window.min;
  161. flushmemscreen(gscreen->r);
  162. }
  163. static void
  164. setscreen(LCDmode *mode)
  165. {
  166. int h;
  167. if(swc != nil)
  168. swcurs_destroy(swc);
  169. vd = lcd_init(mode);
  170. if(vd == nil)
  171. panic("can't initialise LCD");
  172. if(lum[255] == 255) {
  173. int i;
  174. for(i=0; i<256; i++)
  175. lum[i] >>= 4; /* could support depths other than 4 */
  176. }
  177. gscreen = &xgscreen;
  178. xgdata.ref = 1;
  179. if(conf.portrait == 0)
  180. gscreen->r = Rect(0, 0, vd->x, vd->y);
  181. else
  182. gscreen->r = Rect(0, 0, vd->y, vd->x);
  183. gscreen->clipr = gscreen->r;
  184. gscreen->depth = 8;
  185. gscreen->width = wordsperline(gscreen->r, gscreen->depth);
  186. if(vd->depth == 4 || vd->depth == 16 || conf.portrait) { /* use 8 to 4 bit fakeout for speed */
  187. if((xgdata.bdata = xspanalloc(gscreen->width*gscreen->r.max.y*BY2WD+CACHELINESZ, CACHELINESZ, 0)) == nil)
  188. panic("can't alloc vidmem");
  189. xgdata.bdata = minicached(xgdata.bdata);
  190. if(conf.portrait == 0)
  191. flushpixels = vd->depth==4? flush8to4: flush8to16;
  192. else
  193. flushpixels = vd->depth==4? flush8to4r: flush8to16r;
  194. } else{
  195. xgdata.bdata = (uchar*)vd->fb;
  196. flushpixels = nil;
  197. }
  198. memimageinit();
  199. memdefont = getmemdefont();
  200. memsetchan(gscreen, CMAP8); /* TO DO: could now use RGB16 */
  201. back = memwhite;
  202. conscol = memblack;
  203. memimagedraw(gscreen, gscreen->r, memwhite, ZP, memopaque, ZP, SoverD);
  204. DPRINT("vd->wid=%d bwid=%d gscreen->width=%ld fb=%p data=%p\n",
  205. vd->x, vd->bwid, gscreen->width, vd->fb, xgdata.bdata);
  206. graphicscmap(0);
  207. h = memdefont->height;
  208. window = insetrect(gscreen->r, 4);
  209. window.max.y = window.min.y+(Dy(window)/h)*h;
  210. screenclear();
  211. // swc = swcurs_create(gscreendata.data, gscreen.width, gscreen.ldepth, gscreen.r, 1);
  212. drawcursor(nil);
  213. }
  214. void
  215. screeninit(void)
  216. {
  217. LCDmode lcd;
  218. memset(&lcd, 0, sizeof(lcd));
  219. if(archlcdmode(&lcd) < 0)
  220. return;
  221. setscreen(&lcd);
  222. screenputs = lcdscreenputs;
  223. if(printbufpos)
  224. screenputs("", 0);
  225. blanktime = 3; /* minutes */
  226. }
  227. uchar*
  228. attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
  229. {
  230. *r = gscreen->r;
  231. *d = gscreen->depth;
  232. *chan = gscreen->chan;
  233. *width = gscreen->width;
  234. *softscreen = (gscreen->data->bdata != (uchar*)vd->fb);
  235. return (uchar*)gscreen->data->bdata;
  236. }
  237. void
  238. detachscreen(void)
  239. {
  240. }
  241. static void
  242. flush8to4(Rectangle r, ulong *s, int sw, ulong *d, int dw)
  243. {
  244. int i, h, w;
  245. /*
  246. print("1) s=%ux sw=%d d=%ux dw=%d r=(%d,%d)(%d,%d)\n",
  247. s, sw, d, dw, r.min.x, r.min.y, r.max.x, r.max.y);
  248. */
  249. r.min.x &= ~7;
  250. r.max.x = (r.max.x + 7) & ~7;
  251. s += (r.min.y*sw)+(r.min.x>>2);
  252. d += (r.min.y*dw)+(r.min.x>>3);
  253. h = Dy(r);
  254. w = Dx(r) >> 3;
  255. sw -= w*2;
  256. dw -= w;
  257. while(h--) {
  258. for(i=w; i; i--) {
  259. ulong v1 = *s++;
  260. ulong v2 = *s++;
  261. *d++ = (lum[v2>>24]<<28)
  262. |(lum[(v2>>16)&0xff]<<24)
  263. |(lum[(v2>>8)&0xff]<<20)
  264. |(lum[v2&0xff]<<16)
  265. |(lum[v1>>24]<<12)
  266. |(lum[(v1>>16)&0xff]<<8)
  267. |(lum[(v1>>8)&0xff]<<4)
  268. |(lum[v1&0xff])
  269. ;
  270. }
  271. s += sw;
  272. d += dw;
  273. }
  274. }
  275. static void
  276. flush8to16(Rectangle r, ulong *s, int sw, ulong *d, int dw)
  277. {
  278. int i, h, w;
  279. ushort *p;
  280. if(0)
  281. iprint("1) s=%p sw=%d d=%p dw=%d r=[%d,%d, %d,%d]\n",
  282. s, sw, d, dw, r.min.x, r.min.y, r.max.x, r.max.y);
  283. r.min.x &= ~3;
  284. r.max.x = (r.max.x + 3) & ~3; /* nearest ulong */
  285. s += (r.min.y*sw)+(r.min.x>>2);
  286. d += (r.min.y*dw)+(r.min.x>>1);
  287. h = Dy(r);
  288. w = Dx(r) >> 2; /* also ulong */
  289. sw -= w;
  290. dw -= w*2;
  291. if(0)
  292. iprint("h=%d w=%d sw=%d dw=%d\n", h, w, sw, dw);
  293. p = palette16;
  294. while(--h >= 0){
  295. for(i=w; --i>=0;){
  296. ulong v = *s++;
  297. *d++ = (p[(v>>8)&0xFF]<<16) | p[v & 0xFF];
  298. *d++ = (p[v>>24]<<16) | p[(v>>16)&0xFF];
  299. }
  300. s += sw;
  301. d += dw;
  302. }
  303. }
  304. static void
  305. flush8to4r(Rectangle r, ulong *s, int sw, ulong *d, int dw)
  306. {
  307. flush8to4(r, s, sw, d, dw); /* rotation not implemented */
  308. }
  309. static void
  310. flush8to16r(Rectangle r, ulong *s, int sw, ulong *d, int dw)
  311. {
  312. int x, y, w, dws;
  313. ushort *p;
  314. ushort *ds;
  315. if(0)
  316. iprint("1) s=%p sw=%d d=%p dw=%d r=[%d,%d, %d,%d]\n",
  317. s, sw, d, dw, r.min.x, r.min.y, r.max.x, r.max.y);
  318. r.min.y &= ~3;
  319. r.max.y = (r.max.y+3) & ~3;
  320. r.min.x &= ~7;
  321. r.max.x = (r.max.x + 7) & ~7;
  322. s += (r.min.y*sw)+(r.min.x>>2);
  323. // d += (r.min.y*dw)+(r.min.x>>1);
  324. w = Dx(r) >> 2; /* also ulong */
  325. sw -= w;
  326. dws = dw*2;
  327. if(0)
  328. iprint("h=%d w=%d sw=%d dw=%d x,y=%d,%d %d\n", Dy(r), w, sw, dw, r.min.x,r.min.y, dws);
  329. p = palette16;
  330. for(y=r.min.y; y<r.max.y; y++){
  331. for(x=r.min.x; x<r.max.x; x+=4){
  332. ulong v = *s++;
  333. ds = (ushort*)(d + x*dw) + (gscreen->r.max.y-(y+1));
  334. ds[0] = p[v & 0xFF];
  335. ds[dws] = p[(v>>8)&0xFF];
  336. ds[dws*2] = p[(v>>16)&0xFF];
  337. ds[dws*3] = p[(v>>24)&0xFF];
  338. }
  339. s += sw;
  340. }
  341. }
  342. void
  343. flushmemscreen(Rectangle r)
  344. {
  345. if(rectclip(&r, gscreen->r) == 0)
  346. return;
  347. if(r.min.x >= r.max.x || r.min.y >= r.max.y)
  348. return;
  349. if(flushpixels != nil)
  350. flushpixels(r, (ulong*)gscreen->data->bdata, gscreen->width, (ulong*)vd->fb, vd->bwid >> 2);
  351. lcd_flush();
  352. }
  353. static void
  354. scroll(void)
  355. {
  356. int o;
  357. Point p;
  358. Rectangle r;
  359. o = 4*memdefont->height;
  360. r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
  361. p = Pt(window.min.x, window.min.y+o);
  362. memimagedraw(gscreen, r, gscreen, p, nil, p, SoverD);
  363. flushmemscreen(r);
  364. r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
  365. memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
  366. flushmemscreen(r);
  367. curpos.y -= o;
  368. }
  369. static void
  370. clearline(void)
  371. {
  372. Rectangle r;
  373. int yloc = curpos.y;
  374. r = Rpt(Pt(window.min.x, window.min.y + yloc),
  375. Pt(window.max.x, window.min.y+yloc+memdefont->height));
  376. memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
  377. }
  378. static void
  379. screenputc(char *buf)
  380. {
  381. Point p;
  382. int h, w, pos;
  383. Rectangle r;
  384. static int *xp;
  385. static int xbuf[256];
  386. h = memdefont->height;
  387. if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
  388. xp = xbuf;
  389. switch(buf[0]) {
  390. case '\n':
  391. if(curpos.y+h >= window.max.y)
  392. scroll();
  393. curpos.y += h;
  394. /* fall through */
  395. case '\r':
  396. xp = xbuf;
  397. curpos.x = window.min.x;
  398. break;
  399. case '\t':
  400. if(curpos.x == window.min.x)
  401. clearline();
  402. p = memsubfontwidth(memdefont, " ");
  403. w = p.x;
  404. *xp++ = curpos.x;
  405. pos = (curpos.x-window.min.x)/w;
  406. pos = 8-(pos%8);
  407. r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y+h);
  408. memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
  409. flushmemscreen(r);
  410. curpos.x += pos*w;
  411. break;
  412. case '\b':
  413. if(xp <= xbuf)
  414. break;
  415. xp--;
  416. r = Rpt(Pt(*xp, curpos.y), Pt(curpos.x, curpos.y + h));
  417. memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
  418. flushmemscreen(r);
  419. curpos.x = *xp;
  420. break;
  421. case '\0':
  422. break;
  423. default:
  424. p = memsubfontwidth(memdefont, buf);
  425. w = p.x;
  426. if(curpos.x >= window.max.x-w)
  427. screenputc("\n");
  428. if(curpos.x == window.min.x)
  429. clearline();
  430. if(xp < xbuf+nelem(xbuf))
  431. *xp++ = curpos.x;
  432. r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h);
  433. memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD);
  434. memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
  435. flushmemscreen(r);
  436. curpos.x += w;
  437. }
  438. }
  439. static void
  440. screenpbuf(char *s, int n)
  441. {
  442. if(printbufpos+n > sizeof(printbuf))
  443. n = sizeof(printbuf)-printbufpos;
  444. if(n > 0) {
  445. memmove(&printbuf[printbufpos], s, n);
  446. printbufpos += n;
  447. }
  448. }
  449. static void
  450. screendoputs(char *s, int n)
  451. {
  452. int i;
  453. Rune r;
  454. char buf[4];
  455. while(n > 0) {
  456. i = chartorune(&r, s);
  457. if(i == 0){
  458. s++;
  459. --n;
  460. continue;
  461. }
  462. memmove(buf, s, i);
  463. buf[i] = 0;
  464. n -= i;
  465. s += i;
  466. screenputc(buf);
  467. }
  468. }
  469. void
  470. screenflush(void)
  471. {
  472. int j = 0;
  473. int k;
  474. for (k = printbufpos; j < k; k = printbufpos) {
  475. screendoputs(printbuf + j, k - j);
  476. j = k;
  477. }
  478. printbufpos = 0;
  479. }
  480. static void
  481. lcdscreenputs(char *s, int n)
  482. {
  483. static Proc *me;
  484. if(!canlock(vd)) {
  485. /* don't deadlock trying to print in interrupt */
  486. /* don't deadlock trying to print while in print */
  487. if(islo() == 0 || up != nil && up == me){
  488. /* save it for later... */
  489. /* In some cases this allows seeing a panic message
  490. that would be locked out forever */
  491. screenpbuf(s, n);
  492. return;
  493. }
  494. lock(vd);
  495. }
  496. me = up;
  497. if (printbufpos)
  498. screenflush();
  499. screendoputs(s, n);
  500. if (printbufpos)
  501. screenflush();
  502. me = nil;
  503. unlock(vd);
  504. }
  505. /*
  506. * Software cursor code: done by hand, might be better to use memdraw
  507. */
  508. typedef struct SWcursor {
  509. ulong *fb; /* screen frame buffer */
  510. Rectangle r;
  511. int d; /* ldepth of screen */
  512. int width; /* width of screen in ulongs */
  513. int x;
  514. int y;
  515. int hotx;
  516. int hoty;
  517. uchar cbwid; /* cursor byte width */
  518. uchar f; /* flags */
  519. uchar cwid;
  520. uchar chgt;
  521. int hidecount;
  522. uchar data[CURSWID*CURSHGT];
  523. uchar mask[CURSWID*CURSHGT];
  524. uchar save[CURSWID*CURSHGT];
  525. } SWcursor;
  526. enum {
  527. CUR_ENA = 0x01, /* cursor is enabled */
  528. CUR_DRW = 0x02, /* cursor is currently drawn */
  529. CUR_SWP = 0x10, /* bit swap */
  530. };
  531. static Rectangle cursoroffrect;
  532. static int cursorisoff;
  533. static void swcursorflush(int, int);
  534. static void swcurs_draw_or_undraw(SWcursor *);
  535. static void
  536. cursorupdate0(void)
  537. {
  538. int inrect, x, y;
  539. Point m;
  540. m = mousexy();
  541. x = m.x - swc->hotx;
  542. y = m.y - swc->hoty;
  543. inrect = (x >= cursoroffrect.min.x && x < cursoroffrect.max.x
  544. && y >= cursoroffrect.min.y && y < cursoroffrect.max.y);
  545. if (cursorisoff == inrect)
  546. return;
  547. cursorisoff = inrect;
  548. if (inrect)
  549. swcurs_hide(swc);
  550. else {
  551. swc->hidecount = 0;
  552. swcurs_draw_or_undraw(swc);
  553. }
  554. swcursorflush(m.x, m.y);
  555. }
  556. void
  557. cursorupdate(Rectangle r)
  558. {
  559. lock(vd);
  560. r.min.x -= 16;
  561. r.min.y -= 16;
  562. cursoroffrect = r;
  563. if (swc != nil)
  564. cursorupdate0();
  565. unlock(vd);
  566. }
  567. void
  568. cursorenable(void)
  569. {
  570. Point m;
  571. lock(vd);
  572. if(swc != nil) {
  573. swcurs_enable(swc);
  574. m = mousexy();
  575. swcursorflush(m.x, m.y);
  576. }
  577. unlock(vd);
  578. }
  579. void
  580. cursordisable(void)
  581. {
  582. Point m;
  583. lock(vd);
  584. if(swc != nil) {
  585. swcurs_disable(swc);
  586. m = mousexy();
  587. swcursorflush(m.x, m.y);
  588. }
  589. unlock(vd);
  590. }
  591. void
  592. swcursupdate(int oldx, int oldy, int x, int y)
  593. {
  594. if(!canlock(vd))
  595. return; /* if can't lock, don't wake up stuff */
  596. if(x < gscreen->r.min.x)
  597. x = gscreen->r.min.x;
  598. if(x >= gscreen->r.max.x)
  599. x = gscreen->r.max.x;
  600. if(y < gscreen->r.min.y)
  601. y = gscreen->r.min.y;
  602. if(y >= gscreen->r.max.y)
  603. y = gscreen->r.max.y;
  604. if(swc != nil) {
  605. swcurs_hide(swc);
  606. swc->x = x;
  607. swc->y = y;
  608. cursorupdate0();
  609. swcurs_unhide(swc);
  610. swcursorflush(oldx, oldy);
  611. swcursorflush(x, y);
  612. }
  613. unlock(vd);
  614. }
  615. void
  616. drawcursor(Drawcursor* c)
  617. {
  618. Point p, m;
  619. Cursor curs, *cp;
  620. int j, i, h, bpl;
  621. uchar *bc, *bs, *cclr, *cset;
  622. if(swc == nil)
  623. return;
  624. /* Set the default system cursor */
  625. if(c == nil || c->data == nil){
  626. swcurs_disable(swc);
  627. return;
  628. }
  629. else {
  630. cp = &curs;
  631. p.x = c->hotx;
  632. p.y = c->hoty;
  633. cp->offset = p;
  634. bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 1);
  635. h = (c->maxy-c->miny)/2;
  636. if(h > 16)
  637. h = 16;
  638. bc = c->data;
  639. bs = c->data + h*bpl;
  640. cclr = cp->clr;
  641. cset = cp->set;
  642. for(i = 0; i < h; i++) {
  643. for(j = 0; j < 2; j++) {
  644. cclr[j] = bc[j];
  645. cset[j] = bs[j];
  646. }
  647. bc += bpl;
  648. bs += bpl;
  649. cclr += 2;
  650. cset += 2;
  651. }
  652. }
  653. swcurs_load(swc, cp);
  654. m = mousexy();
  655. swcursorflush(m.x, m.y);
  656. swcurs_enable(swc);
  657. }
  658. SWcursor*
  659. swcurs_create(ulong *fb, int width, int ldepth, Rectangle r, int bitswap)
  660. {
  661. SWcursor *swc;
  662. swc = (SWcursor*)malloc(sizeof(SWcursor));
  663. swc->fb = fb;
  664. swc->r = r;
  665. swc->d = ldepth;
  666. swc->width = width;
  667. swc->f = bitswap ? CUR_SWP : 0;
  668. swc->x = swc->y = 0;
  669. swc->hotx = swc->hoty = 0;
  670. swc->hidecount = 0;
  671. return swc;
  672. }
  673. void
  674. swcurs_destroy(SWcursor *swc)
  675. {
  676. swcurs_disable(swc);
  677. free(swc);
  678. }
  679. static void
  680. swcursorflush(int x, int y)
  681. {
  682. Rectangle r;
  683. /* XXX a little too paranoid here */
  684. r.min.x = x-16;
  685. r.min.y = y-16;
  686. r.max.x = x+17;
  687. r.max.y = y+17;
  688. flushmemscreen(r);
  689. }
  690. static void
  691. swcurs_draw_or_undraw(SWcursor *swc)
  692. {
  693. uchar *p;
  694. uchar *cs;
  695. int w, vw;
  696. int x1 = swc->r.min.x;
  697. int y1 = swc->r.min.y;
  698. int x2 = swc->r.max.x;
  699. int y2 = swc->r.max.y;
  700. int xp = swc->x - swc->hotx;
  701. int yp = swc->y - swc->hoty;
  702. int ofs;
  703. if(((swc->f & CUR_ENA) && (swc->hidecount <= 0))
  704. == ((swc->f & CUR_DRW) != 0))
  705. return;
  706. w = swc->cbwid*BI2BY/(1 << swc->d);
  707. x1 = xp < x1 ? x1 : xp;
  708. y1 = yp < y1 ? y1 : yp;
  709. x2 = xp+w >= x2 ? x2 : xp+w;
  710. y2 = yp+swc->chgt >= y2 ? y2 : yp+swc->chgt;
  711. if(x2 <= x1 || y2 <= y1)
  712. return;
  713. p = (uchar*)(swc->fb + swc->width*y1)
  714. + x1*(1 << swc->d)/BI2BY;
  715. y2 -= y1;
  716. x2 = (x2-x1)*(1 << swc->d)/BI2BY;
  717. vw = swc->width*BY2WD - x2;
  718. w = swc->cbwid - x2;
  719. ofs = swc->cbwid*(y1-yp)+(x1-xp);
  720. cs = swc->save + ofs;
  721. if((swc->f ^= CUR_DRW) & CUR_DRW) {
  722. uchar *cm = swc->mask + ofs;
  723. uchar *cd = swc->data + ofs;
  724. while(y2--) {
  725. x1 = x2;
  726. while(x1--) {
  727. *p = ((*cs++ = *p) & *cm++) ^ *cd++;
  728. p++;
  729. }
  730. cs += w;
  731. cm += w;
  732. cd += w;
  733. p += vw;
  734. }
  735. } else {
  736. while(y2--) {
  737. x1 = x2;
  738. while(x1--)
  739. *p++ = *cs++;
  740. cs += w;
  741. p += vw;
  742. }
  743. }
  744. }
  745. void
  746. swcurs_hide(SWcursor *swc)
  747. {
  748. ++swc->hidecount;
  749. swcurs_draw_or_undraw(swc);
  750. }
  751. void
  752. swcurs_unhide(SWcursor *swc)
  753. {
  754. if (--swc->hidecount < 0)
  755. swc->hidecount = 0;
  756. swcurs_draw_or_undraw(swc);
  757. }
  758. void
  759. swcurs_enable(SWcursor *swc)
  760. {
  761. swc->f |= CUR_ENA;
  762. swcurs_draw_or_undraw(swc);
  763. }
  764. void
  765. swcurs_disable(SWcursor *swc)
  766. {
  767. swc->f &= ~CUR_ENA;
  768. swcurs_draw_or_undraw(swc);
  769. }
  770. void
  771. swcurs_load(SWcursor *swc, Cursor *c)
  772. {
  773. int i, k;
  774. uchar *bc, *bs, *cd, *cm;
  775. static uchar bdv[4] = {0,Backgnd,Foregnd,0xff};
  776. static uchar bmv[4] = {0xff,0,0,0xff};
  777. int bits = 1<<swc->d;
  778. uchar mask = (1<<bits)-1;
  779. int bswp = (swc->f&CUR_SWP) ? 8-bits : 0;
  780. bc = c->clr;
  781. bs = c->set;
  782. swcurs_hide(swc);
  783. cd = swc->data;
  784. cm = swc->mask;
  785. swc->hotx = c->offset.x;
  786. swc->hoty = c->offset.y;
  787. swc->chgt = CURSHGT;
  788. swc->cwid = CURSWID;
  789. swc->cbwid = CURSWID*(1<<swc->d)/BI2BY;
  790. for(i = 0; i < CURSWID/BI2BY*CURSHGT; i++) {
  791. uchar bcb = *bc++;
  792. uchar bsb = *bs++;
  793. for(k=0; k<BI2BY;) {
  794. uchar cdv = 0;
  795. uchar cmv = 0;
  796. int z;
  797. for(z=0; z<BI2BY; z += bits) {
  798. int n = ((bsb&(0x80))|((bcb&(0x80))<<1))>>7;
  799. int s = z^bswp;
  800. cdv |= (bdv[n]&mask) << s;
  801. cmv |= (bmv[n]&mask) << s;
  802. bcb <<= 1;
  803. bsb <<= 1;
  804. k++;
  805. }
  806. *cd++ = cdv;
  807. *cm++ = cmv;
  808. }
  809. }
  810. swcurs_unhide(swc);
  811. }