devdraw.c 41 KB

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