devdraw.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148
  1. #include "u.h"
  2. #include "lib.h"
  3. #include "dat.h"
  4. #include "fns.h"
  5. #include "error.h"
  6. #define Image IMAGE
  7. #include <draw.h>
  8. #include <memdraw.h>
  9. #include <memlayer.h>
  10. #include <cursor.h>
  11. #include "screen.h"
  12. enum
  13. {
  14. Qtopdir = 0,
  15. Qnew,
  16. Q3rd,
  17. Q2nd,
  18. Qcolormap,
  19. Qctl,
  20. Qdata,
  21. Qrefresh,
  22. };
  23. /*
  24. * Qid path is:
  25. * 4 bits of file type (qids above)
  26. * 24 bits of mux slot number +1; 0 means not attached to client
  27. */
  28. #define QSHIFT 4 /* location in qid of client # */
  29. #define QID(q) ((((ulong)(q).path)&0x0000000F)>>0)
  30. #define CLIENTPATH(q) ((((ulong)q)&0x7FFFFFF0)>>QSHIFT)
  31. #define CLIENT(q) CLIENTPATH((q).path)
  32. #define NHASH (1<<5)
  33. #define HASHMASK (NHASH-1)
  34. #define IOUNIT (64*1024)
  35. typedef struct Client Client;
  36. typedef struct Draw Draw;
  37. typedef struct DImage DImage;
  38. typedef struct DScreen DScreen;
  39. typedef struct CScreen CScreen;
  40. typedef struct FChar FChar;
  41. typedef struct Refresh Refresh;
  42. typedef struct Refx Refx;
  43. typedef struct DName DName;
  44. ulong blanktime = 30; /* in minutes; a half hour */
  45. struct Draw
  46. {
  47. QLock lk;
  48. int clientid;
  49. int nclient;
  50. Client** client;
  51. int nname;
  52. DName* name;
  53. int vers;
  54. int softscreen;
  55. int blanked; /* screen turned off */
  56. ulong blanktime; /* time of last operation */
  57. ulong savemap[3*256];
  58. };
  59. struct Client
  60. {
  61. Ref r;
  62. DImage* dimage[NHASH];
  63. CScreen* cscreen;
  64. Refresh* refresh;
  65. Rendez refrend;
  66. uchar* readdata;
  67. int nreaddata;
  68. int busy;
  69. int clientid;
  70. int slot;
  71. int refreshme;
  72. int infoid;
  73. int op;
  74. };
  75. struct Refresh
  76. {
  77. DImage* dimage;
  78. Rectangle r;
  79. Refresh* next;
  80. };
  81. struct Refx
  82. {
  83. Client* client;
  84. DImage* dimage;
  85. };
  86. struct DName
  87. {
  88. char *name;
  89. Client *client;
  90. DImage* dimage;
  91. int vers;
  92. };
  93. struct FChar
  94. {
  95. int minx; /* left edge of bits */
  96. int maxx; /* right edge of bits */
  97. uchar miny; /* first non-zero scan-line */
  98. uchar maxy; /* last non-zero scan-line + 1 */
  99. schar left; /* offset of baseline */
  100. uchar width; /* width of baseline */
  101. };
  102. /*
  103. * Reference counts in DImages:
  104. * one per open by original client
  105. * one per screen image or fill
  106. * one per image derived from this one by name
  107. */
  108. struct DImage
  109. {
  110. int id;
  111. int ref;
  112. char *name;
  113. int vers;
  114. Memimage* image;
  115. int ascent;
  116. int nfchar;
  117. FChar* fchar;
  118. DScreen* dscreen; /* 0 if not a window */
  119. DImage* fromname; /* image this one is derived from, by name */
  120. DImage* next;
  121. };
  122. struct CScreen
  123. {
  124. DScreen* dscreen;
  125. CScreen* next;
  126. };
  127. struct DScreen
  128. {
  129. int id;
  130. int public;
  131. int ref;
  132. DImage *dimage;
  133. DImage *dfill;
  134. Memscreen* screen;
  135. Client* owner;
  136. DScreen* next;
  137. };
  138. static Draw sdraw;
  139. static Memimage *screenimage;
  140. static Memdata screendata;
  141. static Rectangle flushrect;
  142. static int waste;
  143. static DScreen* dscreen;
  144. extern void flushmemscreen(Rectangle);
  145. void drawmesg(Client*, void*, int);
  146. void drawuninstall(Client*, int);
  147. void drawfreedimage(DImage*);
  148. Client* drawclientofpath(ulong);
  149. static char Enodrawimage[] = "unknown id for draw image";
  150. static char Enodrawscreen[] = "unknown id for draw screen";
  151. static char Eshortdraw[] = "short draw message";
  152. static char Eshortread[] = "draw read too short";
  153. static char Eimageexists[] = "image id in use";
  154. static char Escreenexists[] = "screen id in use";
  155. static char Edrawmem[] = "image memory allocation failed";
  156. static char Ereadoutside[] = "readimage outside image";
  157. static char Ewriteoutside[] = "writeimage outside image";
  158. static char Enotfont[] = "image not a font";
  159. static char Eindex[] = "character index out of range";
  160. static char Enoclient[] = "no such draw client";
  161. /* static char Edepth[] = "image has bad depth"; */
  162. static char Enameused[] = "image name in use";
  163. static char Enoname[] = "no image with that name";
  164. static char Eoldname[] = "named image no longer valid";
  165. static char Enamed[] = "image already has name";
  166. static char Ewrongname[] = "wrong name for image";
  167. int
  168. drawcanqlock(void)
  169. {
  170. return canqlock(&sdraw.lk);
  171. }
  172. void
  173. drawqlock(void)
  174. {
  175. qlock(&sdraw.lk);
  176. }
  177. void
  178. drawqunlock(void)
  179. {
  180. qunlock(&sdraw.lk);
  181. }
  182. static int
  183. drawgen(Chan *c, char *name, Dirtab *dt, int ndt, int s, Dir *dp)
  184. {
  185. int t;
  186. Qid q;
  187. ulong path;
  188. Client *cl;
  189. USED(name);
  190. USED(dt);
  191. USED(ndt);
  192. q.vers = 0;
  193. if(s == DEVDOTDOT){
  194. switch(QID(c->qid)){
  195. case Qtopdir:
  196. case Q2nd:
  197. mkqid(&q, Qtopdir, 0, QTDIR);
  198. devdir(c, q, "#i", 0, eve, 0500, dp);
  199. break;
  200. case Q3rd:
  201. cl = drawclientofpath(c->qid.path);
  202. if(cl == nil)
  203. strcpy(up->genbuf, "??");
  204. else
  205. sprint(up->genbuf, "%d", cl->clientid);
  206. mkqid(&q, Q2nd, 0, QTDIR);
  207. devdir(c, q, up->genbuf, 0, eve, 0500, dp);
  208. break;
  209. default:
  210. panic("drawwalk %llux", c->qid.path);
  211. }
  212. return 1;
  213. }
  214. /*
  215. * Top level directory contains the name of the device.
  216. */
  217. t = QID(c->qid);
  218. if(t == Qtopdir){
  219. switch(s){
  220. case 0:
  221. mkqid(&q, Q2nd, 0, QTDIR);
  222. devdir(c, q, "draw", 0, eve, 0555, dp);
  223. break;
  224. default:
  225. return -1;
  226. }
  227. return 1;
  228. }
  229. /*
  230. * Second level contains "new" plus all the clients.
  231. */
  232. if(t == Q2nd || t == Qnew){
  233. if(s == 0){
  234. mkqid(&q, Qnew, 0, QTFILE);
  235. devdir(c, q, "new", 0, eve, 0666, dp);
  236. }
  237. else if(s <= sdraw.nclient){
  238. cl = sdraw.client[s-1];
  239. if(cl == 0)
  240. return 0;
  241. sprint(up->genbuf, "%d", cl->clientid);
  242. mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR);
  243. devdir(c, q, up->genbuf, 0, eve, 0555, dp);
  244. return 1;
  245. }
  246. else
  247. return -1;
  248. return 1;
  249. }
  250. /*
  251. * Third level.
  252. */
  253. path = c->qid.path&~((1<<QSHIFT)-1); /* slot component */
  254. q.vers = c->qid.vers;
  255. q.type = QTFILE;
  256. switch(s){
  257. case 0:
  258. q.path = path|Qcolormap;
  259. devdir(c, q, "colormap", 0, eve, 0600, dp);
  260. break;
  261. case 1:
  262. q.path = path|Qctl;
  263. devdir(c, q, "ctl", 0, eve, 0600, dp);
  264. break;
  265. case 2:
  266. q.path = path|Qdata;
  267. devdir(c, q, "data", 0, eve, 0600, dp);
  268. break;
  269. case 3:
  270. q.path = path|Qrefresh;
  271. devdir(c, q, "refresh", 0, eve, 0400, dp);
  272. break;
  273. default:
  274. return -1;
  275. }
  276. return 1;
  277. }
  278. static
  279. int
  280. drawrefactive(void *a)
  281. {
  282. Client *c;
  283. c = a;
  284. return c->refreshme || c->refresh!=0;
  285. }
  286. static
  287. void
  288. drawrefreshscreen(DImage *l, Client *client)
  289. {
  290. while(l != nil && l->dscreen == nil)
  291. l = l->fromname;
  292. if(l != nil && l->dscreen->owner != client)
  293. l->dscreen->owner->refreshme = 1;
  294. }
  295. static
  296. void
  297. drawrefresh(Memimage *m, Rectangle r, void *v)
  298. {
  299. Refx *x;
  300. DImage *d;
  301. Client *c;
  302. Refresh *ref;
  303. USED(m);
  304. if(v == 0)
  305. return;
  306. x = v;
  307. c = x->client;
  308. d = x->dimage;
  309. for(ref=c->refresh; ref; ref=ref->next)
  310. if(ref->dimage == d){
  311. combinerect(&ref->r, r);
  312. return;
  313. }
  314. ref = malloc(sizeof(Refresh));
  315. if(ref){
  316. ref->dimage = d;
  317. ref->r = r;
  318. ref->next = c->refresh;
  319. c->refresh = ref;
  320. }
  321. }
  322. static void
  323. addflush(Rectangle r)
  324. {
  325. int abb, ar, anbb;
  326. Rectangle nbb;
  327. if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
  328. return;
  329. if(flushrect.min.x >= flushrect.max.x){
  330. flushrect = r;
  331. waste = 0;
  332. return;
  333. }
  334. nbb = flushrect;
  335. combinerect(&nbb, r);
  336. ar = Dx(r)*Dy(r);
  337. abb = Dx(flushrect)*Dy(flushrect);
  338. anbb = Dx(nbb)*Dy(nbb);
  339. /*
  340. * Area of new waste is area of new bb minus area of old bb,
  341. * less the area of the new segment, which we assume is not waste.
  342. * This could be negative, but that's OK.
  343. */
  344. waste += anbb-abb - ar;
  345. if(waste < 0)
  346. waste = 0;
  347. /*
  348. * absorb if:
  349. * total area is small
  350. * waste is less than half total area
  351. * rectangles touch
  352. */
  353. if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){
  354. flushrect = nbb;
  355. return;
  356. }
  357. /* emit current state */
  358. if(flushrect.min.x < flushrect.max.x)
  359. flushmemscreen(flushrect);
  360. flushrect = r;
  361. waste = 0;
  362. }
  363. static
  364. void
  365. dstflush(int dstid, Memimage *dst, Rectangle r)
  366. {
  367. Memlayer *l;
  368. if(dstid == 0){
  369. combinerect(&flushrect, r);
  370. return;
  371. }
  372. /* how can this happen? -rsc, dec 12 2002 */
  373. if(dst == 0){
  374. print("nil dstflush\n");
  375. return;
  376. }
  377. l = dst->layer;
  378. if(l == nil)
  379. return;
  380. do{
  381. if(l->screen->image->data != screenimage->data)
  382. return;
  383. r = rectaddpt(r, l->delta);
  384. l = l->screen->image->layer;
  385. }while(l);
  386. addflush(r);
  387. }
  388. void
  389. drawflush(void)
  390. {
  391. if(flushrect.min.x < flushrect.max.x)
  392. flushmemscreen(flushrect);
  393. flushrect = Rect(10000, 10000, -10000, -10000);
  394. }
  395. void
  396. drawflushr(Rectangle r)
  397. {
  398. qlock(&sdraw.lk);
  399. flushmemscreen(r);
  400. qunlock(&sdraw.lk);
  401. }
  402. static
  403. int
  404. drawcmp(char *a, char *b, int n)
  405. {
  406. if(strlen(a) != n)
  407. return 1;
  408. return memcmp(a, b, n);
  409. }
  410. DName*
  411. drawlookupname(int n, char *str)
  412. {
  413. DName *name, *ename;
  414. name = sdraw.name;
  415. ename = &name[sdraw.nname];
  416. for(; name<ename; name++)
  417. if(drawcmp(name->name, str, n) == 0)
  418. return name;
  419. return 0;
  420. }
  421. int
  422. drawgoodname(DImage *d)
  423. {
  424. DName *n;
  425. /* if window, validate the screen's own images */
  426. if(d->dscreen)
  427. if(drawgoodname(d->dscreen->dimage) == 0
  428. || drawgoodname(d->dscreen->dfill) == 0)
  429. return 0;
  430. if(d->name == nil)
  431. return 1;
  432. n = drawlookupname(strlen(d->name), d->name);
  433. if(n==nil || n->vers!=d->vers)
  434. return 0;
  435. return 1;
  436. }
  437. DImage*
  438. drawlookup(Client *client, int id, int checkname)
  439. {
  440. DImage *d;
  441. d = client->dimage[id&HASHMASK];
  442. while(d){
  443. if(d->id == id){
  444. if(checkname && !drawgoodname(d))
  445. error(Eoldname);
  446. return d;
  447. }
  448. d = d->next;
  449. }
  450. return 0;
  451. }
  452. DScreen*
  453. drawlookupdscreen(int id)
  454. {
  455. DScreen *s;
  456. s = dscreen;
  457. while(s){
  458. if(s->id == id)
  459. return s;
  460. s = s->next;
  461. }
  462. return 0;
  463. }
  464. DScreen*
  465. drawlookupscreen(Client *client, int id, CScreen **cs)
  466. {
  467. CScreen *s;
  468. s = client->cscreen;
  469. while(s){
  470. if(s->dscreen->id == id){
  471. *cs = s;
  472. return s->dscreen;
  473. }
  474. s = s->next;
  475. }
  476. error(Enodrawscreen);
  477. return 0;
  478. }
  479. Memimage*
  480. drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
  481. {
  482. DImage *d;
  483. d = malloc(sizeof(DImage));
  484. if(d == 0)
  485. return 0;
  486. d->id = id;
  487. d->ref = 1;
  488. d->name = 0;
  489. d->vers = 0;
  490. d->image = i;
  491. d->nfchar = 0;
  492. d->fchar = 0;
  493. d->fromname = 0;
  494. d->dscreen = dscreen;
  495. d->next = client->dimage[id&HASHMASK];
  496. client->dimage[id&HASHMASK] = d;
  497. return i;
  498. }
  499. Memscreen*
  500. drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
  501. {
  502. Memscreen *s;
  503. CScreen *c;
  504. c = malloc(sizeof(CScreen));
  505. if(dimage && dimage->image && dimage->image->chan == 0)
  506. panic("bad image %p in drawinstallscreen", dimage->image);
  507. if(c == 0)
  508. return 0;
  509. if(d == 0){
  510. d = malloc(sizeof(DScreen));
  511. if(d == 0){
  512. free(c);
  513. return 0;
  514. }
  515. s = malloc(sizeof(Memscreen));
  516. if(s == 0){
  517. free(c);
  518. free(d);
  519. return 0;
  520. }
  521. s->frontmost = 0;
  522. s->rearmost = 0;
  523. d->dimage = dimage;
  524. if(dimage){
  525. s->image = dimage->image;
  526. dimage->ref++;
  527. }
  528. d->dfill = dfill;
  529. if(dfill){
  530. s->fill = dfill->image;
  531. dfill->ref++;
  532. }
  533. d->ref = 0;
  534. d->id = id;
  535. d->screen = s;
  536. d->public = public;
  537. d->next = dscreen;
  538. d->owner = client;
  539. dscreen = d;
  540. }
  541. c->dscreen = d;
  542. d->ref++;
  543. c->next = client->cscreen;
  544. client->cscreen = c;
  545. return d->screen;
  546. }
  547. void
  548. drawdelname(DName *name)
  549. {
  550. int i;
  551. i = name-sdraw.name;
  552. memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
  553. sdraw.nname--;
  554. }
  555. void
  556. drawfreedscreen(DScreen *this)
  557. {
  558. DScreen *ds, *next;
  559. this->ref--;
  560. if(this->ref < 0)
  561. print("negative ref in drawfreedscreen\n");
  562. if(this->ref > 0)
  563. return;
  564. ds = dscreen;
  565. if(ds == this){
  566. dscreen = this->next;
  567. goto Found;
  568. }
  569. while((next = ds->next)){ /* assign = */
  570. if(next == this){
  571. ds->next = this->next;
  572. goto Found;
  573. }
  574. ds = next;
  575. }
  576. error(Enodrawimage);
  577. Found:
  578. if(this->dimage)
  579. drawfreedimage(this->dimage);
  580. if(this->dfill)
  581. drawfreedimage(this->dfill);
  582. free(this->screen);
  583. free(this);
  584. }
  585. void
  586. drawfreedimage(DImage *dimage)
  587. {
  588. int i;
  589. Memimage *l;
  590. DScreen *ds;
  591. dimage->ref--;
  592. if(dimage->ref < 0)
  593. print("negative ref in drawfreedimage\n");
  594. if(dimage->ref > 0)
  595. return;
  596. /* any names? */
  597. for(i=0; i<sdraw.nname; )
  598. if(sdraw.name[i].dimage == dimage)
  599. drawdelname(sdraw.name+i);
  600. else
  601. i++;
  602. if(dimage->fromname){ /* acquired by name; owned by someone else*/
  603. drawfreedimage(dimage->fromname);
  604. goto Return;
  605. }
  606. if(dimage->image == screenimage) /* don't free the display */
  607. goto Return;
  608. ds = dimage->dscreen;
  609. if(ds){
  610. l = dimage->image;
  611. if(l->data == screenimage->data)
  612. addflush(l->layer->screenr);
  613. if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */
  614. free(l->layer->refreshptr);
  615. l->layer->refreshptr = nil;
  616. if(drawgoodname(dimage))
  617. memldelete(l);
  618. else
  619. memlfree(l);
  620. drawfreedscreen(ds);
  621. }else
  622. freememimage(dimage->image);
  623. Return:
  624. free(dimage->fchar);
  625. free(dimage);
  626. }
  627. void
  628. drawuninstallscreen(Client *client, CScreen *this)
  629. {
  630. CScreen *cs, *next;
  631. cs = client->cscreen;
  632. if(cs == this){
  633. client->cscreen = this->next;
  634. drawfreedscreen(this->dscreen);
  635. free(this);
  636. return;
  637. }
  638. while((next = cs->next)){ /* assign = */
  639. if(next == this){
  640. cs->next = this->next;
  641. drawfreedscreen(this->dscreen);
  642. free(this);
  643. return;
  644. }
  645. cs = next;
  646. }
  647. }
  648. void
  649. drawuninstall(Client *client, int id)
  650. {
  651. DImage *d, *next;
  652. d = client->dimage[id&HASHMASK];
  653. if(d == 0)
  654. error(Enodrawimage);
  655. if(d->id == id){
  656. client->dimage[id&HASHMASK] = d->next;
  657. drawfreedimage(d);
  658. return;
  659. }
  660. while((next = d->next)){ /* assign = */
  661. if(next->id == id){
  662. d->next = next->next;
  663. drawfreedimage(next);
  664. return;
  665. }
  666. d = next;
  667. }
  668. error(Enodrawimage);
  669. }
  670. void
  671. drawaddname(Client *client, DImage *di, int n, char *str)
  672. {
  673. DName *name, *ename, *new, *t;
  674. name = sdraw.name;
  675. ename = &name[sdraw.nname];
  676. for(; name<ename; name++)
  677. if(drawcmp(name->name, str, n) == 0)
  678. error(Enameused);
  679. t = smalloc((sdraw.nname+1)*sizeof(DName));
  680. memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
  681. free(sdraw.name);
  682. sdraw.name = t;
  683. new = &sdraw.name[sdraw.nname++];
  684. new->name = smalloc(n+1);
  685. memmove(new->name, str, n);
  686. new->name[n] = 0;
  687. new->dimage = di;
  688. new->client = client;
  689. new->vers = ++sdraw.vers;
  690. }
  691. Client*
  692. drawnewclient(void)
  693. {
  694. Client *cl, **cp;
  695. int i;
  696. for(i=0; i<sdraw.nclient; i++){
  697. cl = sdraw.client[i];
  698. if(cl == 0)
  699. break;
  700. }
  701. if(i == sdraw.nclient){
  702. cp = malloc((sdraw.nclient+1)*sizeof(Client*));
  703. if(cp == 0)
  704. return 0;
  705. memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));
  706. free(sdraw.client);
  707. sdraw.client = cp;
  708. sdraw.nclient++;
  709. cp[i] = 0;
  710. }
  711. cl = malloc(sizeof(Client));
  712. if(cl == 0)
  713. return 0;
  714. memset(cl, 0, sizeof(Client));
  715. cl->slot = i;
  716. cl->clientid = ++sdraw.clientid;
  717. cl->op = SoverD;
  718. sdraw.client[i] = cl;
  719. return cl;
  720. }
  721. static int
  722. drawclientop(Client *cl)
  723. {
  724. int op;
  725. op = cl->op;
  726. cl->op = SoverD;
  727. return op;
  728. }
  729. int
  730. drawhasclients(void)
  731. {
  732. /*
  733. * if draw has ever been used, we can't resize the frame buffer,
  734. * even if all clients have exited (nclients is cumulative); it's too
  735. * hard to make work.
  736. */
  737. return sdraw.nclient != 0;
  738. }
  739. Client*
  740. drawclientofpath(ulong path)
  741. {
  742. Client *cl;
  743. int slot;
  744. slot = CLIENTPATH(path);
  745. if(slot == 0)
  746. return nil;
  747. cl = sdraw.client[slot-1];
  748. if(cl==0 || cl->clientid==0)
  749. return nil;
  750. return cl;
  751. }
  752. Client*
  753. drawclient(Chan *c)
  754. {
  755. Client *client;
  756. client = drawclientofpath(c->qid.path);
  757. if(client == nil)
  758. error(Enoclient);
  759. return client;
  760. }
  761. Memimage*
  762. drawimage(Client *client, uchar *a)
  763. {
  764. DImage *d;
  765. d = drawlookup(client, BGLONG(a), 1);
  766. if(d == nil)
  767. error(Enodrawimage);
  768. return d->image;
  769. }
  770. void
  771. drawrectangle(Rectangle *r, uchar *a)
  772. {
  773. r->min.x = BGLONG(a+0*4);
  774. r->min.y = BGLONG(a+1*4);
  775. r->max.x = BGLONG(a+2*4);
  776. r->max.y = BGLONG(a+3*4);
  777. }
  778. void
  779. drawpoint(Point *p, uchar *a)
  780. {
  781. p->x = BGLONG(a+0*4);
  782. p->y = BGLONG(a+1*4);
  783. }
  784. #define isvgascreen(dst) 1
  785. Point
  786. drawchar(Memimage *dst, Memimage *rdst, Point p,
  787. Memimage *src, Point *sp, DImage *font, int index, int op)
  788. {
  789. FChar *fc;
  790. Rectangle r;
  791. Point sp1;
  792. static Memimage *tmp;
  793. fc = &font->fchar[index];
  794. r.min.x = p.x+fc->left;
  795. r.min.y = p.y-(font->ascent-fc->miny);
  796. r.max.x = r.min.x+(fc->maxx-fc->minx);
  797. r.max.y = r.min.y+(fc->maxy-fc->miny);
  798. sp1.x = sp->x+fc->left;
  799. sp1.y = sp->y+fc->miny;
  800. /*
  801. * If we're drawing greyscale fonts onto a VGA screen,
  802. * it's very costly to read the screen memory to do the
  803. * alpha blending inside memdraw. If this is really a stringbg,
  804. * then rdst is the bg image (in main memory) which we can
  805. * refer to for the underlying dst pixels instead of reading dst
  806. * directly.
  807. */
  808. if(1 || (isvgascreen(dst) && !isvgascreen(rdst) /*&& font->image->depth > 1*/)){
  809. if(tmp == nil || tmp->chan != dst->chan || Dx(tmp->r) < Dx(r) || Dy(tmp->r) < Dy(r)){
  810. if(tmp)
  811. freememimage(tmp);
  812. tmp = allocmemimage(Rect(0,0,Dx(r),Dy(r)), dst->chan);
  813. if(tmp == nil)
  814. goto fallback;
  815. }
  816. memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), rdst, r.min, memopaque, ZP, S);
  817. memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), src, sp1, font->image, Pt(fc->minx, fc->miny), op);
  818. memdraw(dst, r, tmp, ZP, memopaque, ZP, S);
  819. }else{
  820. fallback:
  821. memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
  822. }
  823. p.x += fc->width;
  824. sp->x += fc->width;
  825. return p;
  826. }
  827. static int
  828. initscreenimage(void)
  829. {
  830. int width, depth;
  831. ulong chan;
  832. void *X;
  833. Rectangle r;
  834. if(screenimage != nil)
  835. return 1;
  836. screendata.base = nil;
  837. screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen, &X);
  838. if(screendata.bdata == nil && X == nil)
  839. return 0;
  840. screendata.ref = 1;
  841. screenimage = allocmemimaged(r, chan, &screendata, X);
  842. if(screenimage == nil){
  843. /* RSC: BUG: detach screen */
  844. return 0;
  845. }
  846. screenimage->width = width;
  847. screenimage->clipr = r;
  848. return 1;
  849. }
  850. void
  851. deletescreenimage(void)
  852. {
  853. qlock(&sdraw.lk);
  854. /* RSC: BUG: detach screen */
  855. if(screenimage)
  856. freememimage(screenimage);
  857. screenimage = nil;
  858. qunlock(&sdraw.lk);
  859. }
  860. static Chan*
  861. drawattach(char *spec)
  862. {
  863. qlock(&sdraw.lk);
  864. if(!initscreenimage()){
  865. qunlock(&sdraw.lk);
  866. error("no frame buffer");
  867. }
  868. qunlock(&sdraw.lk);
  869. return devattach('i', spec);
  870. }
  871. static Walkqid*
  872. drawwalk(Chan *c, Chan *nc, char **name, int nname)
  873. {
  874. if(screendata.bdata == nil)
  875. error("no frame buffer");
  876. return devwalk(c, nc, name, nname, 0, 0, drawgen);
  877. }
  878. static int
  879. drawstat(Chan *c, uchar *db, int n)
  880. {
  881. return devstat(c, db, n, 0, 0, drawgen);
  882. }
  883. static Chan*
  884. drawopen(Chan *c, int omode)
  885. {
  886. Client *cl;
  887. if(c->qid.type & QTDIR){
  888. c = devopen(c, omode, 0, 0, drawgen);
  889. c->iounit = IOUNIT;
  890. }
  891. qlock(&sdraw.lk);
  892. if(waserror()){
  893. qunlock(&sdraw.lk);
  894. nexterror();
  895. }
  896. if(QID(c->qid) == Qnew){
  897. cl = drawnewclient();
  898. if(cl == 0)
  899. error(Enodev);
  900. c->qid.path = Qctl|((cl->slot+1)<<QSHIFT);
  901. }
  902. switch(QID(c->qid)){
  903. case Qnew:
  904. break;
  905. case Qctl:
  906. cl = drawclient(c);
  907. if(cl->busy)
  908. error(Einuse);
  909. cl->busy = 1;
  910. flushrect = Rect(10000, 10000, -10000, -10000);
  911. drawinstall(cl, 0, screenimage, 0);
  912. incref(&cl->r);
  913. break;
  914. case Qcolormap:
  915. case Qdata:
  916. case Qrefresh:
  917. cl = drawclient(c);
  918. incref(&cl->r);
  919. break;
  920. }
  921. qunlock(&sdraw.lk);
  922. poperror();
  923. c->mode = openmode(omode);
  924. c->flag |= COPEN;
  925. c->offset = 0;
  926. c->iounit = IOUNIT;
  927. return c;
  928. }
  929. static void
  930. drawclose(Chan *c)
  931. {
  932. int i;
  933. DImage *d, **dp;
  934. Client *cl;
  935. Refresh *r;
  936. if(QID(c->qid) < Qcolormap) /* Qtopdir, Qnew, Q3rd, Q2nd have no client */
  937. return;
  938. qlock(&sdraw.lk);
  939. if(waserror()){
  940. qunlock(&sdraw.lk);
  941. nexterror();
  942. }
  943. cl = drawclient(c);
  944. if(QID(c->qid) == Qctl)
  945. cl->busy = 0;
  946. if((c->flag&COPEN) && (decref(&cl->r)==0)){
  947. while((r = cl->refresh)){ /* assign = */
  948. cl->refresh = r->next;
  949. free(r);
  950. }
  951. /* free names */
  952. for(i=0; i<sdraw.nname; )
  953. if(sdraw.name[i].client == cl)
  954. drawdelname(sdraw.name+i);
  955. else
  956. i++;
  957. while(cl->cscreen)
  958. drawuninstallscreen(cl, cl->cscreen);
  959. /* all screens are freed, so now we can free images */
  960. dp = cl->dimage;
  961. for(i=0; i<NHASH; i++){
  962. while((d = *dp) != nil){
  963. *dp = d->next;
  964. drawfreedimage(d);
  965. }
  966. dp++;
  967. }
  968. sdraw.client[cl->slot] = 0;
  969. drawflush(); /* to erase visible, now dead windows */
  970. free(cl);
  971. }
  972. qunlock(&sdraw.lk);
  973. poperror();
  974. }
  975. long
  976. drawread(Chan *c, void *a, long n, vlong off)
  977. {
  978. int index, m;
  979. ulong red, green, blue;
  980. Client *cl;
  981. uchar *p;
  982. Refresh *r;
  983. DImage *di;
  984. Memimage *i;
  985. ulong offset = off;
  986. char buf[16];
  987. if(c->qid.type & QTDIR)
  988. return devdirread(c, a, n, 0, 0, drawgen);
  989. cl = drawclient(c);
  990. qlock(&sdraw.lk);
  991. if(waserror()){
  992. qunlock(&sdraw.lk);
  993. nexterror();
  994. }
  995. switch(QID(c->qid)){
  996. case Qctl:
  997. if(n < 12*12)
  998. error(Eshortread);
  999. if(cl->infoid < 0)
  1000. error(Enodrawimage);
  1001. if(cl->infoid == 0){
  1002. i = screenimage;
  1003. if(i == nil)
  1004. error(Enodrawimage);
  1005. }else{
  1006. di = drawlookup(cl, cl->infoid, 1);
  1007. if(di == nil)
  1008. error(Enodrawimage);
  1009. i = di->image;
  1010. }
  1011. n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
  1012. cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl,
  1013. i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
  1014. i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
  1015. cl->infoid = -1;
  1016. break;
  1017. case Qcolormap:
  1018. drawactive(1); /* to restore map from backup */
  1019. p = malloc(4*12*256+1);
  1020. if(p == 0)
  1021. error(Enomem);
  1022. m = 0;
  1023. for(index = 0; index < 256; index++){
  1024. getcolor(index, &red, &green, &blue);
  1025. m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24);
  1026. }
  1027. n = readstr(offset, a, n, (char*)p);
  1028. free(p);
  1029. break;
  1030. case Qdata:
  1031. if(cl->readdata == nil)
  1032. error("no draw data");
  1033. if(n < cl->nreaddata)
  1034. error(Eshortread);
  1035. n = cl->nreaddata;
  1036. memmove(a, cl->readdata, cl->nreaddata);
  1037. free(cl->readdata);
  1038. cl->readdata = nil;
  1039. break;
  1040. case Qrefresh:
  1041. if(n < 5*4)
  1042. error(Ebadarg);
  1043. for(;;){
  1044. if(cl->refreshme || cl->refresh)
  1045. break;
  1046. qunlock(&sdraw.lk);
  1047. if(waserror()){
  1048. qlock(&sdraw.lk); /* restore lock for waserror() above */
  1049. nexterror();
  1050. }
  1051. sleep(&cl->refrend, drawrefactive, cl);
  1052. poperror();
  1053. qlock(&sdraw.lk);
  1054. }
  1055. p = a;
  1056. while(cl->refresh && n>=5*4){
  1057. r = cl->refresh;
  1058. BPLONG(p+0*4, r->dimage->id);
  1059. BPLONG(p+1*4, r->r.min.x);
  1060. BPLONG(p+2*4, r->r.min.y);
  1061. BPLONG(p+3*4, r->r.max.x);
  1062. BPLONG(p+4*4, r->r.max.y);
  1063. cl->refresh = r->next;
  1064. free(r);
  1065. p += 5*4;
  1066. n -= 5*4;
  1067. }
  1068. cl->refreshme = 0;
  1069. n = p-(uchar*)a;
  1070. }
  1071. qunlock(&sdraw.lk);
  1072. poperror();
  1073. return n;
  1074. }
  1075. void
  1076. drawwakeall(void)
  1077. {
  1078. Client *cl;
  1079. int i;
  1080. for(i=0; i<sdraw.nclient; i++){
  1081. cl = sdraw.client[i];
  1082. if(cl && (cl->refreshme || cl->refresh))
  1083. wakeup(&cl->refrend);
  1084. }
  1085. }
  1086. static long
  1087. drawwrite(Chan *c, void *a, long n, vlong offset)
  1088. {
  1089. char buf[128], *fields[4], *q;
  1090. Client *cl;
  1091. int i, m, red, green, blue, x;
  1092. USED(offset);
  1093. if(c->qid.type & QTDIR)
  1094. error(Eisdir);
  1095. cl = drawclient(c);
  1096. qlock(&sdraw.lk);
  1097. if(waserror()){
  1098. drawwakeall();
  1099. qunlock(&sdraw.lk);
  1100. nexterror();
  1101. }
  1102. switch(QID(c->qid)){
  1103. case Qctl:
  1104. if(n != 4)
  1105. error("unknown draw control request");
  1106. cl->infoid = BGLONG((uchar*)a);
  1107. break;
  1108. case Qcolormap:
  1109. drawactive(1); /* to restore map from backup */
  1110. m = n;
  1111. n = 0;
  1112. while(m > 0){
  1113. x = m;
  1114. if(x > sizeof(buf)-1)
  1115. x = sizeof(buf)-1;
  1116. q = memccpy(buf, a, '\n', x);
  1117. if(q == 0)
  1118. break;
  1119. i = q-buf;
  1120. n += i;
  1121. a = (char*)a + i;
  1122. m -= i;
  1123. *q = 0;
  1124. if(tokenize(buf, fields, nelem(fields)) != 4)
  1125. error(Ebadarg);
  1126. i = strtoul(fields[0], 0, 0);
  1127. red = strtoul(fields[1], 0, 0);
  1128. green = strtoul(fields[2], 0, 0);
  1129. blue = strtoul(fields[3], &q, 0);
  1130. if(fields[3] == q)
  1131. error(Ebadarg);
  1132. if(red>255 || green>255 || blue>255 || i<0 || i>255)
  1133. error(Ebadarg);
  1134. red |= red<<8;
  1135. red |= red<<16;
  1136. green |= green<<8;
  1137. green |= green<<16;
  1138. blue |= blue<<8;
  1139. blue |= blue<<16;
  1140. setcolor(i, red, green, blue);
  1141. }
  1142. break;
  1143. case Qdata:
  1144. drawmesg(cl, a, n);
  1145. drawwakeall();
  1146. break;
  1147. default:
  1148. error(Ebadusefd);
  1149. }
  1150. qunlock(&sdraw.lk);
  1151. poperror();
  1152. return n;
  1153. }
  1154. uchar*
  1155. drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
  1156. {
  1157. int b, x;
  1158. if(p >= maxp)
  1159. error(Eshortdraw);
  1160. b = *p++;
  1161. x = b & 0x7F;
  1162. if(b & 0x80){
  1163. if(p+1 >= maxp)
  1164. error(Eshortdraw);
  1165. x |= *p++ << 7;
  1166. x |= *p++ << 15;
  1167. if(x & (1<<22))
  1168. x |= ~0<<23;
  1169. }else{
  1170. if(b & 0x40)
  1171. x |= ~0<<7;
  1172. x += oldx;
  1173. }
  1174. *newx = x;
  1175. return p;
  1176. }
  1177. static void
  1178. printmesg(char *fmt, uchar *a, int plsprnt)
  1179. {
  1180. char buf[256];
  1181. char *p, *q;
  1182. int s;
  1183. if(1|| plsprnt==0){
  1184. SET(s);
  1185. SET(q);
  1186. SET(p);
  1187. USED(fmt);
  1188. USED(a);
  1189. USED(buf);
  1190. USED(p);
  1191. USED(q);
  1192. USED(s);
  1193. return;
  1194. }
  1195. q = buf;
  1196. *q++ = *a++;
  1197. for(p=fmt; *p; p++){
  1198. switch(*p){
  1199. case 'l':
  1200. q += sprint(q, " %ld", (long)BGLONG(a));
  1201. a += 4;
  1202. break;
  1203. case 'L':
  1204. q += sprint(q, " %.8lux", (ulong)BGLONG(a));
  1205. a += 4;
  1206. break;
  1207. case 'R':
  1208. q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12));
  1209. a += 16;
  1210. break;
  1211. case 'P':
  1212. q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4));
  1213. a += 8;
  1214. break;
  1215. case 'b':
  1216. q += sprint(q, " %d", *a++);
  1217. break;
  1218. case 's':
  1219. q += sprint(q, " %d", BGSHORT(a));
  1220. a += 2;
  1221. break;
  1222. case 'S':
  1223. q += sprint(q, " %.4ux", BGSHORT(a));
  1224. a += 2;
  1225. break;
  1226. }
  1227. }
  1228. *q++ = '\n';
  1229. *q = 0;
  1230. iprint("%.*s", (int)(q-buf), buf);
  1231. }
  1232. void
  1233. drawmesg(Client *client, void *av, int n)
  1234. {
  1235. int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
  1236. uchar *u, *a, refresh;
  1237. char *fmt;
  1238. ulong value, chan;
  1239. Rectangle r, clipr;
  1240. Point p, q, *pp, sp;
  1241. Memimage *i, *dst, *src, *mask;
  1242. Memimage *l, **lp;
  1243. Memscreen *scrn;
  1244. DImage *font, *ll, *di, *ddst, *dsrc;
  1245. DName *dn;
  1246. DScreen *dscrn;
  1247. FChar *fc;
  1248. Refx *refx;
  1249. CScreen *cs;
  1250. Refreshfn reffn;
  1251. a = av;
  1252. m = 0;
  1253. fmt = nil;
  1254. if(waserror()){
  1255. if(fmt) printmesg(fmt, a, 1);
  1256. /* iprint("error: %s\n", up->errstr); */
  1257. nexterror();
  1258. }
  1259. while((n-=m) > 0){
  1260. USED(fmt);
  1261. a += m;
  1262. switch(*a){
  1263. default:
  1264. error("bad draw command");
  1265. /* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */
  1266. case 'b':
  1267. printmesg(fmt="LLbLbRRL", a, 0);
  1268. m = 1+4+4+1+4+1+4*4+4*4+4;
  1269. if(n < m)
  1270. error(Eshortdraw);
  1271. dstid = BGLONG(a+1);
  1272. scrnid = BGSHORT(a+5);
  1273. refresh = a[9];
  1274. chan = BGLONG(a+10);
  1275. repl = a[14];
  1276. drawrectangle(&r, a+15);
  1277. drawrectangle(&clipr, a+31);
  1278. value = BGLONG(a+47);
  1279. if(drawlookup(client, dstid, 0))
  1280. error(Eimageexists);
  1281. if(scrnid){
  1282. dscrn = drawlookupscreen(client, scrnid, &cs);
  1283. scrn = dscrn->screen;
  1284. if(repl || chan!=scrn->image->chan)
  1285. error("image parameters incompatible with screen");
  1286. reffn = 0;
  1287. switch(refresh){
  1288. case Refbackup:
  1289. break;
  1290. case Refnone:
  1291. reffn = memlnorefresh;
  1292. break;
  1293. case Refmesg:
  1294. reffn = drawrefresh;
  1295. break;
  1296. default:
  1297. error("unknown refresh method");
  1298. }
  1299. l = memlalloc(scrn, r, reffn, 0, value);
  1300. if(l == 0)
  1301. error(Edrawmem);
  1302. addflush(l->layer->screenr);
  1303. l->clipr = clipr;
  1304. rectclip(&l->clipr, r);
  1305. if(drawinstall(client, dstid, l, dscrn) == 0){
  1306. memldelete(l);
  1307. error(Edrawmem);
  1308. }
  1309. dscrn->ref++;
  1310. if(reffn){
  1311. refx = nil;
  1312. if(reffn == drawrefresh){
  1313. refx = malloc(sizeof(Refx));
  1314. if(refx == 0){
  1315. drawuninstall(client, dstid);
  1316. error(Edrawmem);
  1317. }
  1318. refx->client = client;
  1319. refx->dimage = drawlookup(client, dstid, 1);
  1320. }
  1321. memlsetrefresh(l, reffn, refx);
  1322. }
  1323. continue;
  1324. }
  1325. i = allocmemimage(r, chan);
  1326. if(i == 0)
  1327. error(Edrawmem);
  1328. if(repl)
  1329. i->flags |= Frepl;
  1330. i->clipr = clipr;
  1331. if(!repl)
  1332. rectclip(&i->clipr, r);
  1333. if(drawinstall(client, dstid, i, 0) == 0){
  1334. freememimage(i);
  1335. error(Edrawmem);
  1336. }
  1337. memfillcolor(i, value);
  1338. continue;
  1339. /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
  1340. case 'A':
  1341. printmesg(fmt="LLLb", a, 1);
  1342. m = 1+4+4+4+1;
  1343. if(n < m)
  1344. error(Eshortdraw);
  1345. dstid = BGLONG(a+1);
  1346. if(dstid == 0)
  1347. error(Ebadarg);
  1348. if(drawlookupdscreen(dstid))
  1349. error(Escreenexists);
  1350. ddst = drawlookup(client, BGLONG(a+5), 1);
  1351. dsrc = drawlookup(client, BGLONG(a+9), 1);
  1352. if(ddst==0 || dsrc==0)
  1353. error(Enodrawimage);
  1354. if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
  1355. error(Edrawmem);
  1356. continue;
  1357. /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
  1358. case 'c':
  1359. printmesg(fmt="LbR", a, 0);
  1360. m = 1+4+1+4*4;
  1361. if(n < m)
  1362. error(Eshortdraw);
  1363. ddst = drawlookup(client, BGLONG(a+1), 1);
  1364. if(ddst == nil)
  1365. error(Enodrawimage);
  1366. if(ddst->name)
  1367. error("can't change repl/clipr of shared image");
  1368. dst = ddst->image;
  1369. if(a[5])
  1370. dst->flags |= Frepl;
  1371. drawrectangle(&dst->clipr, a+6);
  1372. continue;
  1373. /* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
  1374. case 'd':
  1375. printmesg(fmt="LLLRPP", a, 0);
  1376. m = 1+4+4+4+4*4+2*4+2*4;
  1377. if(n < m)
  1378. error(Eshortdraw);
  1379. dst = drawimage(client, a+1);
  1380. dstid = BGLONG(a+1);
  1381. src = drawimage(client, a+5);
  1382. mask = drawimage(client, a+9);
  1383. drawrectangle(&r, a+13);
  1384. drawpoint(&p, a+29);
  1385. drawpoint(&q, a+37);
  1386. op = drawclientop(client);
  1387. memdraw(dst, r, src, p, mask, q, op);
  1388. dstflush(dstid, dst, r);
  1389. continue;
  1390. /* toggle debugging: 'D' val[1] */
  1391. case 'D':
  1392. printmesg(fmt="b", a, 0);
  1393. m = 1+1;
  1394. if(n < m)
  1395. error(Eshortdraw);
  1396. drawdebug = a[1];
  1397. continue;
  1398. /* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
  1399. case 'e':
  1400. case 'E':
  1401. printmesg(fmt="LLPlllPll", a, 0);
  1402. m = 1+4+4+2*4+4+4+4+2*4+2*4;
  1403. if(n < m)
  1404. error(Eshortdraw);
  1405. dst = drawimage(client, a+1);
  1406. dstid = BGLONG(a+1);
  1407. src = drawimage(client, a+5);
  1408. drawpoint(&p, a+9);
  1409. e0 = BGLONG(a+17);
  1410. e1 = BGLONG(a+21);
  1411. if(e0<0 || e1<0)
  1412. error("invalid ellipse semidiameter");
  1413. j = BGLONG(a+25);
  1414. if(j < 0)
  1415. error("negative ellipse thickness");
  1416. drawpoint(&sp, a+29);
  1417. c = j;
  1418. if(*a == 'E')
  1419. c = -1;
  1420. ox = BGLONG(a+37);
  1421. oy = BGLONG(a+41);
  1422. op = drawclientop(client);
  1423. /* high bit indicates arc angles are present */
  1424. if(ox & (1U<<31)){
  1425. if((ox & (1<<30)) == 0)
  1426. ox &= ~(1U<<31);
  1427. memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
  1428. }else
  1429. memellipse(dst, p, e0, e1, c, src, sp, op);
  1430. dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
  1431. continue;
  1432. /* free: 'f' id[4] */
  1433. case 'f':
  1434. printmesg(fmt="L", a, 1);
  1435. m = 1+4;
  1436. if(n < m)
  1437. error(Eshortdraw);
  1438. ll = drawlookup(client, BGLONG(a+1), 0);
  1439. if(ll && ll->dscreen && ll->dscreen->owner != client)
  1440. ll->dscreen->owner->refreshme = 1;
  1441. drawuninstall(client, BGLONG(a+1));
  1442. continue;
  1443. /* free screen: 'F' id[4] */
  1444. case 'F':
  1445. printmesg(fmt="L", a, 1);
  1446. m = 1+4;
  1447. if(n < m)
  1448. error(Eshortdraw);
  1449. drawlookupscreen(client, BGLONG(a+1), &cs);
  1450. drawuninstallscreen(client, cs);
  1451. continue;
  1452. /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
  1453. case 'i':
  1454. printmesg(fmt="Llb", a, 1);
  1455. m = 1+4+4+1;
  1456. if(n < m)
  1457. error(Eshortdraw);
  1458. dstid = BGLONG(a+1);
  1459. if(dstid == 0)
  1460. error("can't use display as font");
  1461. font = drawlookup(client, dstid, 1);
  1462. if(font == 0)
  1463. error(Enodrawimage);
  1464. if(font->image->layer)
  1465. error("can't use window as font");
  1466. ni = BGLONG(a+5);
  1467. if(ni<=0 || ni>4096)
  1468. error("bad font size (4096 chars max)");
  1469. free(font->fchar); /* should we complain if non-zero? */
  1470. font->fchar = malloc(ni*sizeof(FChar));
  1471. if(font->fchar == 0)
  1472. error("no memory for font");
  1473. memset(font->fchar, 0, ni*sizeof(FChar));
  1474. font->nfchar = ni;
  1475. font->ascent = a[9];
  1476. continue;
  1477. /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
  1478. case 'l':
  1479. printmesg(fmt="LLSRPbb", a, 0);
  1480. m = 1+4+4+2+4*4+2*4+1+1;
  1481. if(n < m)
  1482. error(Eshortdraw);
  1483. font = drawlookup(client, BGLONG(a+1), 1);
  1484. if(font == 0)
  1485. error(Enodrawimage);
  1486. if(font->nfchar == 0)
  1487. error(Enotfont);
  1488. src = drawimage(client, a+5);
  1489. ci = BGSHORT(a+9);
  1490. if(ci >= font->nfchar)
  1491. error(Eindex);
  1492. drawrectangle(&r, a+11);
  1493. drawpoint(&p, a+27);
  1494. memdraw(font->image, r, src, p, memopaque, p, S);
  1495. fc = &font->fchar[ci];
  1496. fc->minx = r.min.x;
  1497. fc->maxx = r.max.x;
  1498. fc->miny = r.min.y;
  1499. fc->maxy = r.max.y;
  1500. fc->left = a[35];
  1501. fc->width = a[36];
  1502. continue;
  1503. /* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
  1504. case 'L':
  1505. printmesg(fmt="LPPlllLP", a, 0);
  1506. m = 1+4+2*4+2*4+4+4+4+4+2*4;
  1507. if(n < m)
  1508. error(Eshortdraw);
  1509. dst = drawimage(client, a+1);
  1510. dstid = BGLONG(a+1);
  1511. drawpoint(&p, a+5);
  1512. drawpoint(&q, a+13);
  1513. e0 = BGLONG(a+21);
  1514. e1 = BGLONG(a+25);
  1515. j = BGLONG(a+29);
  1516. if(j < 0)
  1517. error("negative line width");
  1518. src = drawimage(client, a+33);
  1519. drawpoint(&sp, a+37);
  1520. op = drawclientop(client);
  1521. memline(dst, p, q, e0, e1, j, src, sp, op);
  1522. /* avoid memlinebbox if possible */
  1523. if(dstid==0 || dst->layer!=nil){
  1524. /* BUG: this is terribly inefficient: update maximal containing rect*/
  1525. r = memlinebbox(p, q, e0, e1, j);
  1526. dstflush(dstid, dst, insetrect(r, -(1+1+j)));
  1527. }
  1528. continue;
  1529. /* create image mask: 'm' newid[4] id[4] */
  1530. /*
  1531. *
  1532. case 'm':
  1533. printmesg("LL", a, 0);
  1534. m = 4+4;
  1535. if(n < m)
  1536. error(Eshortdraw);
  1537. break;
  1538. *
  1539. */
  1540. /* attach to a named image: 'n' dstid[4] j[1] name[j] */
  1541. case 'n':
  1542. printmesg(fmt="Lz", a, 0);
  1543. m = 1+4+1;
  1544. if(n < m)
  1545. error(Eshortdraw);
  1546. j = a[5];
  1547. if(j == 0) /* give me a non-empty name please */
  1548. error(Eshortdraw);
  1549. m += j;
  1550. if(n < m)
  1551. error(Eshortdraw);
  1552. dstid = BGLONG(a+1);
  1553. if(drawlookup(client, dstid, 0))
  1554. error(Eimageexists);
  1555. dn = drawlookupname(j, (char*)a+6);
  1556. if(dn == nil)
  1557. error(Enoname);
  1558. if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
  1559. error(Edrawmem);
  1560. di = drawlookup(client, dstid, 0);
  1561. if(di == 0)
  1562. error("draw: can't happen");
  1563. di->vers = dn->vers;
  1564. di->name = smalloc(j+1);
  1565. di->fromname = dn->dimage;
  1566. di->fromname->ref++;
  1567. memmove(di->name, a+6, j);
  1568. di->name[j] = 0;
  1569. client->infoid = dstid;
  1570. continue;
  1571. /* name an image: 'N' dstid[4] in[1] j[1] name[j] */
  1572. case 'N':
  1573. printmesg(fmt="Lbz", a, 0);
  1574. m = 1+4+1+1;
  1575. if(n < m)
  1576. error(Eshortdraw);
  1577. c = a[5];
  1578. j = a[6];
  1579. if(j == 0) /* give me a non-empty name please */
  1580. error(Eshortdraw);
  1581. m += j;
  1582. if(n < m)
  1583. error(Eshortdraw);
  1584. di = drawlookup(client, BGLONG(a+1), 0);
  1585. if(di == 0)
  1586. error(Enodrawimage);
  1587. if(di->name)
  1588. error(Enamed);
  1589. if(c)
  1590. drawaddname(client, di, j, (char*)a+7);
  1591. else{
  1592. dn = drawlookupname(j, (char*)a+7);
  1593. if(dn == nil)
  1594. error(Enoname);
  1595. if(dn->dimage != di)
  1596. error(Ewrongname);
  1597. drawdelname(dn);
  1598. }
  1599. continue;
  1600. /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
  1601. case 'o':
  1602. printmesg(fmt="LPP", a, 0);
  1603. m = 1+4+2*4+2*4;
  1604. if(n < m)
  1605. error(Eshortdraw);
  1606. dst = drawimage(client, a+1);
  1607. if(dst->layer){
  1608. drawpoint(&p, a+5);
  1609. drawpoint(&q, a+13);
  1610. r = dst->layer->screenr;
  1611. ni = memlorigin(dst, p, q);
  1612. if(ni < 0)
  1613. error("image origin failed");
  1614. if(ni > 0){
  1615. addflush(r);
  1616. addflush(dst->layer->screenr);
  1617. ll = drawlookup(client, BGLONG(a+1), 1);
  1618. drawrefreshscreen(ll, client);
  1619. }
  1620. }
  1621. continue;
  1622. /* set compositing operator for next draw operation: 'O' op */
  1623. case 'O':
  1624. printmesg(fmt="b", a, 0);
  1625. m = 1+1;
  1626. if(n < m)
  1627. error(Eshortdraw);
  1628. client->op = a[1];
  1629. continue;
  1630. /* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
  1631. /* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
  1632. case 'p':
  1633. case 'P':
  1634. printmesg(fmt="LslllLPP", a, 0);
  1635. m = 1+4+2+4+4+4+4+2*4;
  1636. if(n < m)
  1637. error(Eshortdraw);
  1638. dstid = BGLONG(a+1);
  1639. dst = drawimage(client, a+1);
  1640. ni = BGSHORT(a+5);
  1641. if(ni < 0)
  1642. error("negative count in polygon");
  1643. e0 = BGLONG(a+7);
  1644. e1 = BGLONG(a+11);
  1645. j = 0;
  1646. if(*a == 'p'){
  1647. j = BGLONG(a+15);
  1648. if(j < 0)
  1649. error("negative polygon line width");
  1650. }
  1651. src = drawimage(client, a+19);
  1652. drawpoint(&sp, a+23);
  1653. drawpoint(&p, a+31);
  1654. ni++;
  1655. pp = malloc(ni*sizeof(Point));
  1656. if(pp == nil)
  1657. error(Enomem);
  1658. doflush = 0;
  1659. if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
  1660. doflush = 1; /* simplify test in loop */
  1661. ox = oy = 0;
  1662. esize = 0;
  1663. u = a+m;
  1664. for(y=0; y<ni; y++){
  1665. q = p;
  1666. oesize = esize;
  1667. u = drawcoord(u, a+n, ox, &p.x);
  1668. u = drawcoord(u, a+n, oy, &p.y);
  1669. ox = p.x;
  1670. oy = p.y;
  1671. if(doflush){
  1672. esize = j;
  1673. if(*a == 'p'){
  1674. if(y == 0){
  1675. c = memlineendsize(e0);
  1676. if(c > esize)
  1677. esize = c;
  1678. }
  1679. if(y == ni-1){
  1680. c = memlineendsize(e1);
  1681. if(c > esize)
  1682. esize = c;
  1683. }
  1684. }
  1685. if(*a=='P' && e0!=1 && e0 !=~0)
  1686. r = dst->clipr;
  1687. else if(y > 0){
  1688. r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1);
  1689. combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
  1690. }
  1691. if(rectclip(&r, dst->clipr)) /* should perhaps be an arg to dstflush */
  1692. dstflush(dstid, dst, r);
  1693. }
  1694. pp[y] = p;
  1695. }
  1696. if(y == 1)
  1697. dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
  1698. op = drawclientop(client);
  1699. if(*a == 'p')
  1700. mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
  1701. else
  1702. memfillpoly(dst, pp, ni, e0, src, sp, op);
  1703. free(pp);
  1704. m = u-a;
  1705. continue;
  1706. /* read: 'r' id[4] R[4*4] */
  1707. case 'r':
  1708. printmesg(fmt="LR", a, 0);
  1709. m = 1+4+4*4;
  1710. if(n < m)
  1711. error(Eshortdraw);
  1712. i = drawimage(client, a+1);
  1713. drawrectangle(&r, a+5);
  1714. if(!rectinrect(r, i->r))
  1715. error(Ereadoutside);
  1716. c = bytesperline(r, i->depth);
  1717. c *= Dy(r);
  1718. free(client->readdata);
  1719. client->readdata = mallocz(c, 0);
  1720. if(client->readdata == nil)
  1721. error("readimage malloc failed");
  1722. client->nreaddata = memunload(i, r, client->readdata, c);
  1723. if(client->nreaddata < 0){
  1724. free(client->readdata);
  1725. client->readdata = nil;
  1726. error("bad readimage call");
  1727. }
  1728. continue;
  1729. /* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
  1730. /* stringbg: 'x' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] bgid[4] bgpt[2*4] ni*(index[2]) */
  1731. case 's':
  1732. case 'x':
  1733. printmesg(fmt="LLLPRPs", a, 0);
  1734. m = 1+4+4+4+2*4+4*4+2*4+2;
  1735. if(*a == 'x')
  1736. m += 4+2*4;
  1737. if(n < m)
  1738. error(Eshortdraw);
  1739. dst = drawimage(client, a+1);
  1740. dstid = BGLONG(a+1);
  1741. src = drawimage(client, a+5);
  1742. font = drawlookup(client, BGLONG(a+9), 1);
  1743. if(font == 0)
  1744. error(Enodrawimage);
  1745. if(font->nfchar == 0)
  1746. error(Enotfont);
  1747. drawpoint(&p, a+13);
  1748. drawrectangle(&r, a+21);
  1749. drawpoint(&sp, a+37);
  1750. ni = BGSHORT(a+45);
  1751. u = a+m;
  1752. m += ni*2;
  1753. if(n < m)
  1754. error(Eshortdraw);
  1755. clipr = dst->clipr;
  1756. dst->clipr = r;
  1757. op = drawclientop(client);
  1758. l = dst;
  1759. if(*a == 'x'){
  1760. /* paint background */
  1761. l = drawimage(client, a+47);
  1762. drawpoint(&q, a+51);
  1763. r.min.x = p.x;
  1764. r.min.y = p.y-font->ascent;
  1765. r.max.x = p.x;
  1766. r.max.y = r.min.y+Dy(font->image->r);
  1767. j = ni;
  1768. while(--j >= 0){
  1769. ci = BGSHORT(u);
  1770. if(ci<0 || ci>=font->nfchar){
  1771. dst->clipr = clipr;
  1772. error(Eindex);
  1773. }
  1774. r.max.x += font->fchar[ci].width;
  1775. u += 2;
  1776. }
  1777. memdraw(dst, r, l, q, memopaque, ZP, op);
  1778. u -= 2*ni;
  1779. }
  1780. q = p;
  1781. while(--ni >= 0){
  1782. ci = BGSHORT(u);
  1783. if(ci<0 || ci>=font->nfchar){
  1784. dst->clipr = clipr;
  1785. error(Eindex);
  1786. }
  1787. q = drawchar(dst, l, q, src, &sp, font, ci, op);
  1788. u += 2;
  1789. }
  1790. dst->clipr = clipr;
  1791. p.y -= font->ascent;
  1792. dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
  1793. continue;
  1794. /* use public screen: 'S' id[4] chan[4] */
  1795. case 'S':
  1796. printmesg(fmt="Ll", a, 0);
  1797. m = 1+4+4;
  1798. if(n < m)
  1799. error(Eshortdraw);
  1800. dstid = BGLONG(a+1);
  1801. if(dstid == 0)
  1802. error(Ebadarg);
  1803. dscrn = drawlookupdscreen(dstid);
  1804. if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
  1805. error(Enodrawscreen);
  1806. if(dscrn->screen->image->chan != BGLONG(a+5))
  1807. error("inconsistent chan");
  1808. if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
  1809. error(Edrawmem);
  1810. continue;
  1811. /* top or bottom windows: 't' top[1] nw[2] n*id[4] */
  1812. case 't':
  1813. printmesg(fmt="bsL", a, 0);
  1814. m = 1+1+2;
  1815. if(n < m)
  1816. error(Eshortdraw);
  1817. nw = BGSHORT(a+2);
  1818. if(nw < 0)
  1819. error(Ebadarg);
  1820. if(nw == 0)
  1821. continue;
  1822. m += nw*4;
  1823. if(n < m)
  1824. error(Eshortdraw);
  1825. lp = malloc(nw*sizeof(Memimage*));
  1826. if(lp == 0)
  1827. error(Enomem);
  1828. if(waserror()){
  1829. free(lp);
  1830. nexterror();
  1831. }
  1832. for(j=0; j<nw; j++)
  1833. lp[j] = drawimage(client, a+1+1+2+j*4);
  1834. if(lp[0]->layer == 0)
  1835. error("images are not windows");
  1836. for(j=1; j<nw; j++)
  1837. if(lp[j]->layer->screen != lp[0]->layer->screen)
  1838. error("images not on same screen");
  1839. if(a[1])
  1840. memltofrontn(lp, nw);
  1841. else
  1842. memltorearn(lp, nw);
  1843. if(lp[0]->layer->screen->image->data == screenimage->data)
  1844. for(j=0; j<nw; j++)
  1845. addflush(lp[j]->layer->screenr);
  1846. ll = drawlookup(client, BGLONG(a+1+1+2), 1);
  1847. drawrefreshscreen(ll, client);
  1848. poperror();
  1849. free(lp);
  1850. continue;
  1851. /* visible: 'v' */
  1852. case 'v':
  1853. printmesg(fmt="", a, 0);
  1854. m = 1;
  1855. drawflush();
  1856. continue;
  1857. /* write: 'y' id[4] R[4*4] data[x*1] */
  1858. /* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */
  1859. case 'y':
  1860. case 'Y':
  1861. printmesg(fmt="LR", a, 0);
  1862. // iprint("load %c\n", *a);
  1863. m = 1+4+4*4;
  1864. if(n < m)
  1865. error(Eshortdraw);
  1866. dstid = BGLONG(a+1);
  1867. dst = drawimage(client, a+1);
  1868. drawrectangle(&r, a+5);
  1869. if(!rectinrect(r, dst->r))
  1870. error(Ewriteoutside);
  1871. y = memload(dst, r, a+m, n-m, *a=='Y');
  1872. if(y < 0)
  1873. error("bad writeimage call");
  1874. dstflush(dstid, dst, r);
  1875. m += y;
  1876. continue;
  1877. }
  1878. }
  1879. poperror();
  1880. }
  1881. Dev drawdevtab = {
  1882. 'i',
  1883. "draw",
  1884. devreset,
  1885. devinit,
  1886. devshutdown,
  1887. drawattach,
  1888. drawwalk,
  1889. drawstat,
  1890. drawopen,
  1891. devcreate,
  1892. drawclose,
  1893. drawread,
  1894. devbread,
  1895. drawwrite,
  1896. devbwrite,
  1897. devremove,
  1898. devwstat,
  1899. };
  1900. /*
  1901. * On 8 bit displays, load the default color map
  1902. */
  1903. void
  1904. drawcmap(void)
  1905. {
  1906. int r, g, b, cr, cg, cb, v;
  1907. int num, den;
  1908. int i, j;
  1909. drawactive(1); /* to restore map from backup */
  1910. for(r=0,i=0; r!=4; r++)
  1911. for(v=0; v!=4; v++,i+=16){
  1912. for(g=0,j=v-r; g!=4; g++)
  1913. for(b=0;b!=4;b++,j++){
  1914. den = r;
  1915. if(g > den)
  1916. den = g;
  1917. if(b > den)
  1918. den = b;
  1919. if(den == 0) /* divide check -- pick grey shades */
  1920. cr = cg = cb = v*17;
  1921. else{
  1922. num = 17*(4*den+v);
  1923. cr = r*num/den;
  1924. cg = g*num/den;
  1925. cb = b*num/den;
  1926. }
  1927. setcolor(i+(j&15),
  1928. cr*0x01010101, cg*0x01010101, cb*0x01010101);
  1929. }
  1930. }
  1931. }
  1932. void
  1933. drawblankscreen(int blank)
  1934. {
  1935. int i, nc;
  1936. ulong *p;
  1937. if(blank == sdraw.blanked)
  1938. return;
  1939. if(!canqlock(&sdraw.lk))
  1940. return;
  1941. if(!initscreenimage()){
  1942. qunlock(&sdraw.lk);
  1943. return;
  1944. }
  1945. p = sdraw.savemap;
  1946. nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth;
  1947. /*
  1948. * blankscreen uses the hardware to blank the screen
  1949. * when possible. to help in cases when it is not possible,
  1950. * we set the color map to be all black.
  1951. */
  1952. if(blank == 0){ /* turn screen on */
  1953. for(i=0; i<nc; i++, p+=3)
  1954. setcolor(i, p[0], p[1], p[2]);
  1955. // blankscreen(0);
  1956. }else{ /* turn screen off */
  1957. // blankscreen(1);
  1958. for(i=0; i<nc; i++, p+=3){
  1959. getcolor(i, &p[0], &p[1], &p[2]);
  1960. setcolor(i, 0, 0, 0);
  1961. }
  1962. }
  1963. sdraw.blanked = blank;
  1964. qunlock(&sdraw.lk);
  1965. }
  1966. /*
  1967. * record activity on screen, changing blanking as appropriate
  1968. */
  1969. void
  1970. drawactive(int active)
  1971. {
  1972. /*
  1973. if(active){
  1974. drawblankscreen(0);
  1975. sdraw.blanktime = MACHP(0)->ticks;
  1976. }else{
  1977. if(blanktime && sdraw.blanktime && TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60 >= blanktime)
  1978. drawblankscreen(1);
  1979. }
  1980. */
  1981. }
  1982. int
  1983. drawidletime(void)
  1984. {
  1985. return 0;
  1986. /* return TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60; */
  1987. }