PageRenderTime 81ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 1ms

/sys/src/cmd/vnc/devdraw.c

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