devdraw.c 40 KB

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