devdraw.c 41 KB

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