1implement Drawmux; 2 3include "sys.m"; 4include "draw.m"; 5include "drawmux.m"; 6 7include "drawoffs.m"; 8 9sys : Sys; 10draw : Draw; 11 12Display, Point, Rect, Chans : import draw; 13 14Ehungup : con "Hangup"; 15 16drawR: Draw->Rect; 17drawchans: Draw->Chans; 18drawop := Draw->SoverD; 19drawfd: ref Sys->FD; 20images: ref Imageset; 21screens: ref Screenset; 22viewers: list of ref Viewer; 23drawlock: chan of chan of int; 24readdata: array of byte; 25nhangups := 0; 26prevnhangups := 0; 27 28init() : (string, ref Draw->Display) 29{ 30 sys = load Sys Sys->PATH; 31 draw = load Draw Draw->PATH; 32 33 if (draw == nil) 34 return (sys->sprint("cannot load %s: %r", Draw->PATH), nil); 35 drawlock = chan of chan of int; 36 images = Imageset.new(); 37 screens = Screenset. new(); 38 res := chan of (string, ref Draw->Display); 39 spawn getdisp(res); 40 r := <- res; 41 return r; 42} 43 44newviewer(fd : ref Sys->FD) 45{ 46 reply := array of byte sys->sprint("%.11d %.11d ", drawR.max.x - drawR.min.x, drawR.max.y - drawR.min.y); 47 if (sys->write(fd, reply, len reply) != len reply) { 48# sys->print("viewer hangup\n"); 49 return; 50 } 51 52 buf := array [Sys->ATOMICIO] of byte; 53 n := sys->read(fd, buf, len buf); 54 if (n < 24) 55 return; 56 pubscr := int string buf[0:12]; 57 chans := Chans.mk(string buf[12:24]); 58 59 sys->pctl(Sys->FORKNS, nil); 60 sys->mount(fd, nil, "/", Sys->MREPL, nil); 61 cfd := sys->open("/new", Sys->OREAD); 62 sys->read(cfd, buf, len buf); 63 cnum := int string buf[0:12]; 64 cdata := sys->sprint("/%d/data", cnum); 65 datafd := sys->open(cdata, Sys->ORDWR); 66 67 if (datafd == nil) { 68# sys->print("cannot open viewer data file: %r\n"); 69 return; 70 } 71 Viewer.new(datafd, pubscr, chans); 72} 73 74getdisp(result : chan of (string, ref Draw->Display)) 75{ 76 sys->pctl(Sys->FORKNS, nil); 77 sys->bind("#i", "/dev", Sys->MREPL); 78 sys->bind("#s", "/dev/draw", Sys->MBEFORE); 79 newio := sys->file2chan("/dev/draw", "new"); 80 if (newio == nil) { 81 result <- = ("cannot create /dev/new file2chan", nil); 82 return; 83 } 84 spawn srvnew(newio); 85 disp := Display.allocate(nil); 86 if (disp == nil) { 87 result <-= (sys->sprint("%r"), nil); 88 return; 89 } 90 91 draw->disp.image.draw(disp.image.r, disp.rgb(0,0,0), nil, Point(0,0)); 92 result <- = (nil, disp); 93} 94 95srvnew(newio : ref Sys->FileIO) 96{ 97 for (;;) alt { 98 (offset, count, fid, rc) := <- newio.read => 99 if (rc != nil) { 100 c := chan of (string, ref Sys->FD); 101 fd := sys->open("#i/draw/new", Sys->OREAD); 102 # +1 because of a sprint() nasty in devdraw.c 103 buf := array [(12 * 12)+1] of byte; 104 nn := sys->read(fd, buf, len buf); 105 cnum := int string buf[0:12]; 106 drawchans = Chans.mk(string buf[24:36]); 107 # repl is at [36:48] 108 drawR.min.x = int string buf[48:60]; 109 drawR.min.y = int string buf[60:72]; 110 drawR.max.x = int string buf[72:84]; 111 drawR.max.y = int string buf[84:96]; 112 113 bwidth := bytesperline(drawR, drawchans); 114 img := ref Image (0, 0, 0, 0, drawchans, 0, drawR, drawR, Draw->Black, nil, drawR.min, bwidth, 0, ""); 115 images.add(0, img); 116 117 cdir := sys->sprint("/dev/draw/%d", cnum); 118 dpath := sys->sprint("#i/draw/%d/data", cnum); 119 drawfd = sys->open(dpath, Sys->ORDWR); 120 fd = nil; 121 if (drawfd == nil) { 122 rc <-= (nil, sys->sprint("%r")); 123 return; 124 } 125 sys->bind("#s", cdir, Sys->MBEFORE); 126 drawio := sys->file2chan(cdir, "data"); 127 spawn drawclient(drawio); 128 rc <- = (buf, nil); 129 return; 130 } 131 (offset, data, fid, wc) := <- newio.write => 132 if (wc != nil) 133 writereply(wc, (0, "permission denied")); 134 } 135} 136 137# for simplicity make the file 'exclusive use' 138drawclient(drawio : ref Sys->FileIO) 139{ 140 activefid := -1; 141 closecount := 2; 142 143 for (;closecount;) { 144 alt { 145 unlock := <- drawlock => 146 <- unlock; 147 148 (offset, count, fid, rc) := <- drawio.read => 149 if (activefid == -1) 150 activefid = fid; 151 152 if (rc == nil) { 153 closecount--; 154 continue; 155 } 156 if (fid != activefid) { 157 rc <-= (nil, "file busy"); 158 continue; 159 } 160 if (readdata == nil) { 161 rc <-= (nil, nil); 162 continue; 163 } 164 if (count > len readdata) 165 count = len readdata; 166 rc <- = (readdata[0:count], nil); 167 readdata = nil; 168 169 (offset, data, fid, wc) := <- drawio.write => 170 if (wc == nil) { 171 closecount--; 172 continue; 173 } 174 writereply(wc, process(data)); 175 } 176 if (nhangups != prevnhangups) { 177 ok : list of ref Viewer; 178 for (ok = nil; viewers != nil; viewers = tl viewers) { 179 v := hd viewers; 180 if (!v.hungup) 181 ok = v :: ok; 182 else { 183# sys->print("shutting down Viewer\n"); 184 v.output <- = (nil, nil); 185 } 186 } 187 viewers = ok; 188 prevnhangups = nhangups; 189 } 190 } 191# sys->print("DRAWIO DONE!\n"); 192} 193 194writereply(wc : chan of (int, string), val : (int, string)) 195{ 196 alt { 197 wc <-= val => 198 ; 199 * => 200 ; 201 } 202} 203 204Image: adt { 205 id: int; 206 refc: int; 207 screenid: int; 208 refresh: int; 209 chans: Draw->Chans; 210 repl: int; 211 R: Draw->Rect; 212 clipR: Draw->Rect; 213 rrggbbaa: int; 214 font: ref Font; 215 lorigin: Draw->Point; 216 bwidth: int; 217 dirty: int; 218 name: string; 219}; 220 221Screen: adt { 222 id: int; 223 imageid: int; 224 fillid: int; 225 windows: array of int; 226 227 setz: fn (s: self ref Screen, z: array of int, top: int); 228 addwin: fn (s: self ref Screen, wid: int); 229 delwin: fn (s: self ref Screen, wid: int); 230}; 231 232Font: adt { 233 ascent: int; 234 chars: array of ref Fontchar; 235}; 236 237Fontchar: adt { 238 srcid: int; 239 R: Draw->Rect; 240 P: Draw->Point; 241 left: int; 242 width: int; 243}; 244 245Idpair: adt { 246 key: int; 247 val: int; 248 next: cyclic ref Idpair; 249}; 250 251Idmap: adt { 252 buckets: array of ref Idpair; 253 254 new: fn (): ref Idmap; 255 add: fn (m: self ref Idmap, key, val: int); 256 del: fn (m: self ref Idmap, key: int); 257 lookup: fn (m: self ref Idmap, key: int): int; 258}; 259 260Imageset: adt { 261 images: array of ref Image; 262 ixmap: ref Idmap; 263 freelist: list of int; 264 new: fn (): ref Imageset; 265 add: fn (s: self ref Imageset, id: int, img: ref Image); 266 del: fn (s: self ref Imageset, id: int); 267 lookup: fn (s: self ref Imageset, id: int): ref Image; 268 findname: fn(s: self ref Imageset, name: string): ref Image; 269}; 270 271Screenset: adt { 272 screens: array of ref Screen; 273 ixmap: ref Idmap; 274 freelist: list of int; 275 new: fn (): ref Screenset; 276 add: fn (s: self ref Screenset, scr: ref Screen); 277 del: fn (s: self ref Screenset, id: int); 278 lookup: fn (s: self ref Screenset, id: int): ref Screen; 279}; 280 281 282Drawreq: adt { 283 data: array of byte; 284 pick { 285# a => # allocate image 286# id: int; 287# screenid: int; 288# refresh: int; 289# ldepth: int; 290# repl: int; 291# R: Draw->Rect; 292# clipR: Draw->Rect; 293# value: int; 294 b => # new allocate image 295 id: int; 296 screenid: int; 297 refresh: int; 298 chans: Draw->Chans; 299 repl: int; 300 R: Draw->Rect; 301 clipR: Draw->Rect; 302 rrggbbaa: int; 303 A => # allocate screen 304 id: int; 305 imageid: int; 306 fillid: int; 307 c => # set clipr and repl 308 dstid: int; 309 repl: int; 310 clipR: Draw->Rect; 311# x => # move cursor 312# C => # set cursor image and hotspot 313# _: int; 314 d => # general draw op 315 dstid: int; 316 srcid: int; 317 maskid: int; 318 D => # debug mode 319 _: int; 320 e => # draw ellipse 321 dstid: int; 322 srcid: int; 323 f => # free image 324 id: int; 325 img: ref Image; # helper for Viewers 326 F => # free screen 327 id: int; 328 i => # convert image to font 329 fontid: int; 330 nchars: int; 331 ascent: int; 332 l => # load a char into font 333 fontid: int; 334 srcid: int; 335 index: int; 336 R: Draw->Rect; 337 P: Draw->Point; 338 left: int; 339 width: int; 340 L => # draw line 341 dstid: int; 342 srcid: int; 343 n => # attach to named image 344 dstid: int; 345 name: string; 346 N => # name image 347 dstid: int; 348 in: int; 349 name: string; 350 o => # set window origins 351 id: int; 352 rmin: Draw->Point; 353 screenrmin: Draw->Point; 354 O => # set next compositing op 355 op: int; 356 p => # draw polygon 357 dstid: int; 358 srcid: int; 359 r => # read pixels 360 id: int; 361 R: Draw->Rect; 362 s => # draw text 363 dstid: int; 364 srcid: int; 365 fontid: int; 366 x => # draw text with bg 367 dstid: int; 368 srcid: int; 369 fontid: int; 370 bgid: int; 371 S => # import public screen 372 t => # adjust window z order 373 top: int; 374 ids: array of int; 375 v => # flush updates to display 376 y => # write pixels 377 id: int; 378 R: Draw->Rect; 379 } 380}; 381 382getreq(data : array of byte, ix : int) : (ref Drawreq, string) 383{ 384 mlen := 0; 385 err := "short draw message"; 386 req : ref Drawreq; 387 388 case int data[ix] { 389 'b' => # alloc image 390 mlen = 1+4+4+1+4+1+(4*4)+(4*4)+4; 391 if (mlen+ix <= len data) { 392 data = data[ix:ix+mlen]; 393 r := ref Drawreq.b; 394 r.data = data; 395 r.id = get4(data, OPb_id); 396 r.screenid = get4(data, OPb_screenid); 397 r.refresh = get1(data, OPb_refresh); 398 r.chans = Draw->Chans(get4(data, OPb_chans)); 399 r.repl = get1(data, OPb_repl); 400 r.R = getR(data, OPb_R); 401 r.clipR = getR(data, OPb_clipR); 402 r.rrggbbaa = get4(data, OPb_rrggbbaa); 403 req = r; 404 } 405 'A' => # alloc screen 406 mlen = 1+4+4+4+1; 407 if (mlen+ix <= len data) { 408 data = data[ix:ix+mlen]; 409 r := ref Drawreq.A; 410 r.data = data; 411 r.id = get4(data, OPA_id); 412 r.imageid = get4(data, OPA_imageid); 413 r.fillid = get4(data, OPA_fillid); 414 req = r; 415 } 416 'c' => # set clipR 417 mlen = 1+4+1+(4*4); 418 if (mlen+ix <= len data) { 419 data = data[ix:ix+mlen]; 420 r := ref Drawreq.c; 421 r.data = data; 422 r.dstid = get4(data, OPc_dstid); 423 r.repl = get1(data, OPc_repl); 424 r.clipR = getR(data, OPc_clipR); 425 req = r; 426 } 427 'd' => # draw 428 mlen = 1+4+4+4+(4*4)+(2*4)+(2*4); 429 if (mlen+ix <= len data) { 430 data = data[ix:ix+mlen]; 431 r := ref Drawreq.d; 432 r.data = data; 433 r.dstid = get4(data, OPd_dstid); 434 r.srcid = get4(data, OPd_srcid); 435 r.maskid = get4(data, OPd_maskid); 436 req = r; 437 } 438 'D' => 439 # debug mode 440 mlen = 1+1; 441 if (mlen+ix <= len data) { 442 req = ref Drawreq.v; 443 req.data = data[ix:ix+mlen]; 444 } 445 'e' or 446 'E' => # ellipse 447 mlen = 1+4+4+(2*4)+4+4+4+(2*4)+4+4; 448 if (mlen+ix <= len data) { 449 data = data[ix:ix+mlen]; 450 r := ref Drawreq.e; 451 r.data = data; 452 r.dstid = get4(data, OPe_dstid); 453 r.srcid = get4(data, OPe_srcid); 454 req = r; 455 } 456 'f' => # free image 457 mlen = 1+4; 458 if (mlen+ix <= len data) { 459 data = data[ix:ix+mlen]; 460 r := ref Drawreq.f; 461 r.data = data; 462 r.id = get4(data, OPf_id); 463 req = r; 464 } 465 'F' => # free screen 466 mlen = 1+4; 467 if (mlen+ix <= len data) { 468 data = data[ix:ix+mlen]; 469 r := ref Drawreq.f; 470 r.data = data; 471 r.id = get4(data, OPF_id); 472 req = r; 473 } 474 'i' => # alloc font 475 mlen = 1+4+4+1; 476 if (mlen+ix <= len data) { 477 data = data[ix:ix+mlen]; 478 r := ref Drawreq.i; 479 r.data = data; 480 r.fontid = get4(data, OPi_fontid); 481 r.nchars = get4(data, OPi_nchars); 482 r.ascent = get1(data, OPi_ascent); 483 req = r; 484 } 485 'l' => # load font char 486 mlen = 1+4+4+2+(4*4)+(2*4)+1+1; 487 if (mlen+ix <= len data) { 488 data = data[ix:ix+mlen]; 489 r := ref Drawreq.l; 490 r.data = data; 491 r.fontid = get4(data, OPl_fontid); 492 r.srcid = get4(data, OPl_srcid); 493 r.index = get2(data, OPl_index); 494 r.R = getR(data, OPl_R); 495 r.P = getP(data, OPl_P); 496 r.left = get1(data, OPl_left); 497 r.width = get1(data, OPl_width); 498 req = r; 499 } 500 'L' => # line 501 mlen = 1+4+(2*4)+(2*4)+4+4+4+4+(2*4); 502 if (mlen+ix <= len data) { 503 data = data[ix:ix+mlen]; 504 r := ref Drawreq.L; 505 r.data = data; 506 r.dstid = get4(data, OPL_dstid); 507 r.srcid = get4(data, OPL_srcid); 508 req = r; 509 } 510 'n' => # attach to named image 511 mlen = 1+4+1; 512 if (mlen+ix < len data) { 513 mlen += get1(data, ix+OPn_j); 514 if (mlen+ix <= len data) { 515 data = data[ix:ix+mlen]; 516 r := ref Drawreq.n; 517 r.data = data; 518 r.dstid = get4(data, OPn_dstid); 519 r.name = string data[OPn_name:]; 520 req = r; 521 } 522 } 523 'N' => # name image 524 mlen = 1+4+1+1; 525 if (mlen+ix < len data) { 526 mlen += get1(data, ix+OPN_j); 527 if (mlen+ix <= len data) { 528 data = data[ix:ix+mlen]; 529 r := ref Drawreq.N; 530 r.data = data; 531 r.dstid = get4(data, OPN_dstid); 532 r.in = get1(data, OPN_in); 533 r.name = string data[OPN_name:]; 534 req = r; 535 } 536 } 537 'o' => # set origins 538 mlen = 1+4+(2*4)+(2*4); 539 if (mlen+ix <= len data) { 540 data = data[ix:ix+mlen]; 541 r := ref Drawreq.o; 542 r.data = data; 543 r.id = get4(data, OPo_id); 544 r.rmin = getP(data, OPo_rmin); 545 r.screenrmin = getP(data, OPo_screenrmin); 546 req = r; 547 } 548 'O' => # set next compop 549 mlen = 1+1; 550 if (mlen+ix <= len data) { 551 data = data[ix:ix+mlen]; 552 r := ref Drawreq.O; 553 r.data = data; 554 r.op = get1(data, OPO_op); 555 req = r; 556 } 557 'p' or 558 'P' => # polygon 559 mlen = 1+4+2+4+4+4+4+(2*4); 560 if (mlen + ix <= len data) { 561 n := get2(data, ix+OPp_n); 562 nb := coordslen(data, ix+OPp_P0, 2*(n+1)); 563 if (nb == -1) 564 err = "bad coords"; 565 else { 566 mlen += nb; 567 if (mlen+ix <= len data) { 568 data = data[ix:ix+mlen]; 569 r := ref Drawreq.p; 570 r.data = data; 571 r.dstid = get4(data, OPp_dstid); 572 r.srcid = get4(data, OPp_srcid); 573 req = r; 574 } 575 } 576 } 577 'r' => # read pixels 578 mlen = 1+4+(4*4); 579 if (mlen+ix <= len data) { 580 data = data[ix:ix+mlen]; 581 r := ref Drawreq.r; 582 r.data = data; 583 r.id = get4(data, OPr_id); 584 r.R = getR(data, OPr_R); 585 req = r; 586 } 587 's' => # text 588 mlen = 1+4+4+4+(2*4)+(4*4)+(2*4)+2; 589 if (ix+mlen <= len data) { 590 ni := get2(data, ix+OPs_ni); 591 mlen += (2*ni); 592 if (mlen+ix <= len data) { 593 data = data[ix:ix+mlen]; 594 r := ref Drawreq.s; 595 r.data = data; 596 r.dstid = get4(data, OPs_dstid); 597 r.srcid = get4(data, OPs_srcid); 598 r.fontid = get4(data, OPs_fontid); 599 req = r; 600 } 601 } 602 'x' => # text with bg img 603 mlen = 1+4+4+4+(2*4)+(4*4)+(2*4)+2+4+(2*4); 604 if (ix+mlen <= len data) { 605 ni := get2(data, ix+OPx_ni); 606 mlen += (2*ni); 607 if (mlen+ix <= len data) { 608 data = data[ix:ix+mlen]; 609 r := ref Drawreq.x; 610 r.data = data; 611 r.dstid = get4(data, OPx_dstid); 612 r.srcid = get4(data, OPx_srcid); 613 r.fontid = get4(data, OPx_fontid); 614 r.bgid = get4(data, OPx_bgid); 615 req = r; 616 } 617 } 618 'S' => # import public screen 619 mlen = 1+4+4; 620 if (mlen+ix <= len data) { 621 data = data[ix:ix+mlen]; 622 req = ref Drawreq.S; 623 req.data = data; 624 } 625 't' => # adjust window z order 626 mlen = 1+1+2; 627 if (ix+mlen<= len data) { 628 nw := get2(data, ix+OPt_nw); 629 mlen += (4*nw); 630 if (mlen+ix <= len data) { 631 data = data[ix:ix+mlen]; 632 r := ref Drawreq.t; 633 r.data = data; 634 r.top = get1(data, OPt_top); 635 r.ids = array [nw] of int; 636 for (n := 0; n < nw; n++) 637 r.ids[n] = get4(data, OPt_id + 4*n); 638 req = r; 639 } 640 } 641 'v' => # flush 642 req = ref Drawreq.v; 643 req.data = data[ix:ix+1]; 644 'y' or 645 'Y' => # write pixels 646 mlen = 1+4+(4*4); 647 if (ix+mlen <= len data) { 648 imgid := get4(data, ix+OPy_id); 649 img := images.lookup(imgid); 650 compd := data[ix] == byte 'Y'; 651 r := getR(data, ix+OPy_R); 652 n := imglen(img, data, ix+mlen, r, compd); 653 if (n == -1) 654 err ="bad image data"; 655 mlen += n; 656 if (mlen+ix <= len data) 657 req = ref Drawreq.y (data[ix:ix+mlen], imgid, r); 658 } 659 * => 660 err = "bad draw command"; 661 } 662 663 if (req == nil) 664 return (nil, err); 665 return (req, nil); 666} 667 668process(data : array of byte) : (int, string) 669{ 670 offset := 0; 671 while (offset < len data) { 672 (req, err) := getreq(data, offset); 673 if (err != nil) 674 return (0, err); 675 offset += len req.data; 676 n := sys->write(drawfd, req.data, len req.data); 677 if (n <= 0) 678 return (n, sys->sprint("[%c] %r", int req.data[0])); 679 680 readn := 0; 681 sendtoviews := 1; 682 683 # actions that must be done before sending to Viewers 684 pick r := req { 685 b => # allocate image 686 bwidth := bytesperline(r.R, r.chans); 687 img := ref Image (r.id, 0, r.screenid, r.refresh, r.chans, r.repl, r.R, r.clipR, r.rrggbbaa, nil, r.R.min, bwidth, 0, ""); 688 images.add(r.id, img); 689 if (r.screenid != 0) { 690 scr := screens.lookup(r.screenid); 691 scr.addwin(r.id); 692 } 693 694 A => # allocate screen 695 scr := ref Screen (r.id, r.imageid, r.fillid, nil); 696 screens.add(scr); 697 # we never allocate public screens on our Viewers 698 put1(r.data, OPA_public, 0); 699 dirty(r.imageid, 0); 700 701 c => # set clipr and repl 702 img := images.lookup(r.dstid); 703 img.repl = r.repl; 704 img.clipR = r.clipR; 705 706 d => # general draw op 707 dirty(r.dstid, 1); 708 drawop = Draw->SoverD; 709 710 e => # draw ellipse 711 dirty(r.dstid, 1); 712 drawop = Draw->SoverD; 713 714 f => # free image 715 # help out Viewers, real work is done later 716 r.img = images.lookup(r.id); 717 718 L => # draw line 719 dirty(r.dstid, 1); 720 drawop = Draw->SoverD; 721 722 n => # attach to named image 723 img := images.findname(r.name); 724 images.add(r.dstid, img); 725 726 N => # name image 727 img := images.lookup(r.dstid); 728 if (r.in) 729 img.name = r.name; 730 else 731 img.name = nil; 732 733 o => # set image origins 734 img := images.lookup(r.id); 735 deltax := img.lorigin.x - r.rmin.x; 736 deltay := img.lorigin.y - r.rmin.y; 737 w := img.R.max.x - img.R.min.x; 738 h := img.R.max.y - img.R.min.y; 739 740 img.R = Draw->Rect(r.screenrmin, (r.screenrmin.x + w, r.screenrmin.y + h)); 741 img.clipR = Draw->Rect((img.clipR.min.x - deltax, img.clipR.min.y - deltay), (img.clipR.max.x - deltax, img.clipR.max.y - deltay)); 742 img.lorigin = r.rmin; 743 744 O => # set compositing op 745 drawop = r.op; 746 747 p => # draw polygon 748 dirty(r.dstid, 1); 749 drawop = Draw->SoverD; 750 751 r => # read pixels 752 img := images.lookup(r.id); 753 bpl := bytesperline(r.R, img.chans); 754 readn = bpl * (r.R.max.y - r.R.min.y); 755 756 s => # draw text 757 dirty(r.dstid, 1); 758 drawop = Draw->SoverD; 759 760 x => # draw text with bg 761 dirty(r.dstid, 1); 762 drawop = Draw->SoverD; 763 764 t => # adjust window z order 765 if (r.ids != nil) { 766 img := images.lookup(r.ids[0]); 767 scr := screens.lookup(img.screenid); 768 scr.setz(r.ids, r.top); 769 } 770 771 y => # write pixels 772 dirty(r.id, 1); 773 } 774 775 if (readn) { 776 rdata := array [readn] of byte; 777 if (sys->read(drawfd, rdata, readn) == readn) 778 readdata = rdata; 779 } 780 781 for (vs := viewers; vs != nil; vs = tl vs) { 782 v := hd vs; 783 v.process(req); 784 } 785 786 # actions that must only be done after sending to Viewers 787 pick r := req { 788 f => # free image 789 img := images.lookup(r.id); 790 if (img.screenid != 0) { 791 scr := screens.lookup(img.screenid); 792 scr.delwin(img.id); 793 } 794 images.del(r.id); 795 796 F => # free screen 797 scr := screens.lookup(r.id); 798 for (i := 0; i < len scr.windows; i++) { 799 img := images.lookup(scr.windows[i]); 800 img.screenid = 0; 801 } 802 screens.del(r.id); 803 804 i => # convert image to font 805 img := images.lookup(r.fontid); 806 font := ref Font; 807 font.ascent = r.ascent; 808 font.chars = array[r.nchars] of ref Fontchar; 809 img.font = font; 810 811 l => # load a char into font 812 img := images.lookup(r.fontid); 813 font := img.font; 814 fc := ref Fontchar(r.srcid, r.R, r.P, r.left, r.width); 815 font.chars[r.index] = fc; 816 } 817 } 818 return (offset, nil); 819} 820 821coordslen(data : array of byte, ix, n : int) : int 822{ 823 start := ix; 824 dlen := len data; 825 if (ix == dlen) 826 return -1; 827 while (ix < dlen && n) { 828 n--; 829 if ((int data[ix++]) & 16r80) 830 ix += 2; 831 } 832 if (n) 833 return -1; 834 return ix - start; 835} 836 837 838imglen(i : ref Image, data : array of byte, ix : int, r : Draw->Rect, comp : int) : int 839{ 840 bpl := bytesperline(r, i.chans); 841 if (!comp) 842 return (r.max.y - r.min.y) * bpl; 843 y := r.min.y; 844 lineix := byteaddr(i, r.min); 845 elineix := lineix+bpl; 846 start := ix; 847 eix := len data; 848 for (;;) { 849 if (lineix == elineix) { 850 if (++y == r.max.y) 851 break; 852 lineix = byteaddr(i, Point(r.min.x, y)); 853 elineix = lineix+bpl; 854 } 855 if (ix == eix) # buffer too small 856 return -1; 857 c := int data[ix++]; 858 if (c >= 128) { 859 for (cnt := c-128+1; cnt != 0; --cnt) { 860 if (ix == eix) # buffer too small 861 return -1; 862 if (lineix == elineix) # phase error 863 return -1; 864 lineix++; 865 ix++; 866 } 867 } else { 868 if (ix == eix) # short buffer 869 return -1; 870 ix++; 871 for (cnt := (c >> 2)+3; cnt != 0; --cnt) { 872 if (lineix == elineix) # phase error 873 return -1; 874 lineix++; 875 } 876 } 877 } 878 return ix-start; 879} 880 881byteaddr(i: ref Image, p: Point): int 882{ 883 x := p.x - i.lorigin.x; 884 y := p.y - i.lorigin.y; 885 bits := i.chans.depth(); 886 if (bits == 0) 887 # invalid chans 888 return 0; 889 return (y*i.bwidth)+(x<<3)/bits; 890} 891 892bytesperline(r: Draw->Rect, chans: Draw->Chans): int 893{ 894 d := chans.depth(); 895 l, t: int; 896 897 if(r.min.x >= 0){ 898 l = (r.max.x*d+8-1)/8; 899 l -= (r.min.x*d)/8; 900 }else{ # make positive before divide 901 t = (-r.min.x*d+8-1)/8; 902 l = t+(r.max.x*d+8-1)/8; 903 } 904 return l; 905} 906 907get1(data : array of byte, ix : int) : int 908{ 909 return int data[ix]; 910} 911 912put1(data : array of byte, ix, val : int) 913{ 914 data[ix] = byte val; 915} 916 917get2(data : array of byte, ix : int) : int 918{ 919 return int data[ix] | ((int data[ix+1]) << 8); 920} 921 922put2(data : array of byte, ix, val : int) 923{ 924 data[ix] = byte val; 925 data[ix+1] = byte (val >> 8); 926} 927 928get4(data : array of byte, ix : int) : int 929{ 930 return int data[ix] | ((int data[ix+1]) << 8) | ((int data[ix+2]) << 16) | ((int data[ix+3]) << 24); 931} 932 933put4(data : array of byte, ix, val : int) 934{ 935 data[ix] = byte val; 936 data[ix+1] = byte (val >> 8); 937 data[ix+2] = byte (val >> 16); 938 data[ix+3] = byte (val >> 24); 939} 940 941getP(data : array of byte, ix : int) : Draw->Point 942{ 943 x := int data[ix] | ((int data[ix+1]) << 8) | ((int data[ix+2]) << 16) | ((int data[ix+3]) << 24); 944 ix += 4; 945 y := int data[ix] | ((int data[ix+1]) << 8) | ((int data[ix+2]) << 16) | ((int data[ix+3]) << 24); 946 return Draw->Point(x, y); 947} 948 949putP(data : array of byte, ix : int, P : Draw->Point) 950{ 951 val := P.x; 952 data[ix] = byte val; 953 data[ix+1] = byte (val >> 8); 954 data[ix+2] = byte (val >> 16); 955 data[ix+3] = byte (val >> 24); 956 val = P.y; 957 ix += 4; 958 data[ix] = byte val; 959 data[ix+1] = byte (val >> 8); 960 data[ix+2] = byte (val >> 16); 961 data[ix+3] = byte (val >> 24); 962} 963 964getR(data : array of byte, ix : int) : Draw->Rect 965{ 966 minx := int data[ix] | ((int data[ix+1]) << 8) | ((int data[ix+2]) << 16) | ((int data[ix+3]) << 24); 967 ix += 4; 968 miny := int data[ix] | ((int data[ix+1]) << 8) | ((int data[ix+2]) << 16) | ((int data[ix+3]) << 24); 969 ix += 4; 970 maxx := int data[ix] | ((int data[ix+1]) << 8) | ((int data[ix+2]) << 16) | ((int data[ix+3]) << 24); 971 ix += 4; 972 maxy := int data[ix] | ((int data[ix+1]) << 8) | ((int data[ix+2]) << 16) | ((int data[ix+3]) << 24); 973 974 return Draw->Rect(Draw->Point(minx, miny), Draw->Point(maxx, maxy)); 975} 976 977putR(data : array of byte, ix : int , R : Draw->Rect) 978{ 979 val := R.min.x; 980 data[ix] = byte val; 981 data[ix+1] = byte (val >> 8); 982 data[ix+2] = byte (val >> 16); 983 data[ix+3] = byte (val >> 24); 984 val = R.min.y; 985 ix += 4; 986 data[ix] = byte val; 987 data[ix+1] = byte (val >> 8); 988 data[ix+2] = byte (val >> 16); 989 data[ix+3] = byte (val >> 24); 990 val = R.max.x; 991 ix += 4; 992 data[ix] = byte val; 993 data[ix+1] = byte (val >> 8); 994 data[ix+2] = byte (val >> 16); 995 data[ix+3] = byte (val >> 24); 996 val = R.max.y; 997 ix += 4; 998 data[ix] = byte val; 999 data[ix+1] = byte (val >> 8); 1000 data[ix+2] = byte (val >> 16); 1001 data[ix+3] = byte (val >> 24); 1002} 1003 1004dirty(id, v : int) 1005{ 1006 img := images.lookup(id); 1007 img.dirty = v; 1008} 1009 1010Screen.setz(s : self ref Screen, z : array of int, top : int) 1011{ 1012 old := s.windows; 1013 nw := array [len old] of int; 1014 # use a dummy idmap to ensure uniqueness; 1015 ids := Idmap.new(); 1016 ix := 0; 1017 if (top) { 1018 for (i := 0; i < len z; i++) { 1019 if (ids.lookup(z[i]) == -1) { 1020 ids.add(z[i], 0); 1021 nw[ix++] = z[i]; 1022 } 1023 } 1024 } 1025 for (i := 0; i < len old; i++) { 1026 if (ids.lookup(old[i]) == -1) { 1027 ids.add(old[i], 0); 1028 nw[ix++] = old[i]; 1029 } 1030 } 1031 if (!top) { 1032 for (i = 0; i < len z; i++) { 1033 if (ids.lookup(z[i]) == -1) { 1034 ids.add(z[i], 0); 1035 nw[ix++] = z[i]; 1036 } 1037 } 1038 } 1039 s.windows = nw; 1040} 1041 1042Screen.addwin(s : self ref Screen, wid : int) 1043{ 1044 nw := array [len s.windows + 1] of int; 1045 nw[0] = wid; 1046 nw[1:] = s.windows; 1047 s.windows = nw; 1048} 1049 1050Screen.delwin(s : self ref Screen, wid : int) 1051{ 1052 if (len s.windows == 1) { 1053 # assert s.windows[0] == wid 1054 s.windows = nil; 1055 return; 1056 } 1057 nw := array [len s.windows - 1] of int; 1058 ix := 0; 1059 for (i := 0; i < len s.windows; i++) { 1060 if (s.windows[i] == wid) 1061 continue; 1062 nw[ix++] = s.windows[i]; 1063 } 1064 s.windows = nw; 1065} 1066 1067Idmap.new() : ref Idmap 1068{ 1069 m := ref Idmap; 1070 m.buckets = array[256] of ref Idpair; 1071 return m; 1072} 1073 1074Idmap.add(m : self ref Idmap, key, val : int) 1075{ 1076 h := key & 16rff; 1077 m.buckets[h] = ref Idpair (key, val, m.buckets[h]); 1078} 1079 1080Idmap.del(m : self ref Idmap, key : int) 1081{ 1082 h := key &16rff; 1083 prev := m.buckets[h]; 1084 if (prev == nil) 1085 return; 1086 if (prev.key == key) { 1087 m.buckets[h] = m.buckets[h].next; 1088 return; 1089 } 1090 for (idp := prev.next; idp != nil; idp = idp.next) { 1091 if (idp.key == key) 1092 break; 1093 prev = idp; 1094 } 1095 if (idp != nil) 1096 prev.next = idp.next; 1097} 1098 1099Idmap.lookup(m :self ref Idmap, key : int) : int 1100{ 1101 h := key &16rff; 1102 for (idp := m.buckets[h]; idp != nil; idp = idp.next) { 1103 if (idp.key == key) 1104 return idp.val; 1105 } 1106 return -1; 1107} 1108 1109Imageset.new() : ref Imageset 1110{ 1111 s := ref Imageset; 1112 s.images = array [32] of ref Image; 1113 s.ixmap = Idmap.new(); 1114 for (i := 0; i < len s.images; i++) 1115 s.freelist = i :: s.freelist; 1116 return s; 1117} 1118 1119Imageset.add(s: self ref Imageset, id: int, img: ref Image) 1120{ 1121 if (s.freelist == nil) { 1122 n := 2 * len s.images; 1123 ni := array [n] of ref Image; 1124 ni[:] = s.images; 1125 for (i := len s.images; i < n; i++) 1126 s.freelist = i :: s.freelist; 1127 s.images = ni; 1128 } 1129 ix := hd s.freelist; 1130 s.freelist = tl s.freelist; 1131 s.images[ix] = img; 1132 s.ixmap.add(id, ix); 1133 img.refc++; 1134} 1135 1136Imageset.del(s: self ref Imageset, id: int) 1137{ 1138 ix := s.ixmap.lookup(id); 1139 if (ix == -1) 1140 return; 1141 img := s.images[ix]; 1142 if (img != nil) 1143 img.refc--; 1144 s.images[ix] = nil; 1145 s.freelist = ix :: s.freelist; 1146 s.ixmap.del(id); 1147} 1148 1149Imageset.lookup(s : self ref Imageset, id : int ) : ref Image 1150{ 1151 ix := s.ixmap.lookup(id); 1152 if (ix == -1) 1153 return nil; 1154 return s.images[ix]; 1155} 1156 1157Imageset.findname(s: self ref Imageset, name: string): ref Image 1158{ 1159 for (ix := 0; ix < len s.images; ix++) { 1160 img := s.images[ix]; 1161 if (img != nil && img.name == name) 1162 return img; 1163 } 1164 return nil; 1165} 1166 1167Screenset.new() : ref Screenset 1168{ 1169 s := ref Screenset; 1170 s.screens = array [32] of ref Screen; 1171 s.ixmap = Idmap.new(); 1172 for (i := 0; i < len s.screens; i++) 1173 s.freelist = i :: s.freelist; 1174 return s; 1175} 1176 1177Screenset.add(s : self ref Screenset, scr : ref Screen) 1178{ 1179 if (s.freelist == nil) { 1180 n := 2 * len s.screens; 1181 ns := array [n] of ref Screen; 1182 ns[:] = s.screens; 1183 for (i := len s.screens; i < n; i++) 1184 s.freelist = i :: s.freelist; 1185 s.screens = ns; 1186 } 1187 ix := hd s.freelist; 1188 s.freelist = tl s.freelist; 1189 s.screens[ix] = scr; 1190 s.ixmap.add(scr.id, ix); 1191} 1192 1193Screenset.del(s : self ref Screenset, id : int) 1194{ 1195 ix := s.ixmap.lookup(id); 1196 if (ix == -1) 1197 return; 1198 s.screens[ix] = nil; 1199 s.freelist = ix :: s.freelist; 1200 s.ixmap.del(id); 1201} 1202 1203Screenset.lookup(s : self ref Screenset, id : int ) : ref Screen 1204{ 1205 ix := s.ixmap.lookup(id); 1206 if (ix == -1) 1207 return nil; 1208 return s.screens[ix]; 1209} 1210 1211 1212Viewer : adt { 1213 imgmap: ref Idmap; 1214 scrmap: ref Idmap; 1215 chanmap: ref Idmap; # maps to 1 for images that require chan conversion 1216 1217 imageid: int; 1218 screenid: int; 1219 whiteid: int; 1220 hungup: int; 1221 dchans: Draw->Chans; # chans.desc of remote display img 1222 1223 # temporary image for chan conversion 1224 tmpid: int; 1225 tmpR: Draw->Rect; 1226 1227 output: chan of (array of byte, chan of string); 1228 1229 new: fn(fd: ref Sys->FD, pubscr: int, chans: Draw->Chans): string; 1230 process: fn(v: self ref Viewer, req: ref Drawreq); 1231 getimg: fn(v: self ref Viewer, id: int): int; 1232 getscr: fn(v: self ref Viewer, id, win: int): (int, int); 1233 copyimg: fn(v: self ref Viewer, img: ref Image, id: int); 1234 chanconv: fn(v: self ref Viewer, img: ref Image, id: int, r: Rect, ymsg: array of byte); 1235}; 1236 1237vwriter(fd : ref Sys->FD, datac : chan of array of byte, nc : chan of string) 1238{ 1239 for (;;) { 1240 data := <- datac; 1241 if (data == nil) 1242 return; 1243 n := sys->write(fd, data, len data); 1244 if (n != len data) { 1245# sys->print("[%c]: %r\n", int data[0]); 1246# sys->print("[%c] datalen %d got %d error: %r\n", int data[0], len data, n); 1247 nc <-= sys->sprint("%r"); 1248 } else { 1249# sys->print("[%c]", int data[0]); 1250 nc <-= nil; 1251 } 1252 } 1253} 1254 1255vbmsg : adt { 1256 data : array of byte; 1257 rc : chan of string; 1258 next : cyclic ref vbmsg; 1259}; 1260 1261vbuffer(v : ref Viewer, fd : ref Sys->FD) 1262{ 1263 ioc := v.output; 1264 datac := chan of array of byte; 1265 errc := chan of string; 1266 spawn vwriter(fd, datac, errc); 1267 fd = nil; 1268 1269 msghd : ref vbmsg; 1270 msgtl : ref vbmsg; 1271 1272Loop: 1273 for (;;) alt { 1274 (data, rc) := <- ioc => 1275 if (data == nil) 1276 break Loop; 1277 if (msgtl != nil) { 1278 if (msgtl != msghd && msgtl.rc == nil && (len msgtl.data + len data) <= Sys->ATOMICIO) { 1279 ndata := array [len msgtl.data + len data] of byte; 1280 ndata[:] = msgtl.data; 1281 ndata[len msgtl.data:] = data; 1282 msgtl.data = ndata; 1283 msgtl.rc = rc; 1284 } else { 1285 msgtl.next = ref vbmsg (data, rc, nil); 1286 msgtl = msgtl.next; 1287 } 1288 } else { 1289 msghd = ref vbmsg (data, rc, nil); 1290 msgtl = msghd; 1291 datac <-= data; 1292 } 1293 err := <- errc => 1294 if (msghd.rc != nil) 1295 msghd.rc <- = err; 1296 msghd = msghd.next; 1297 if (msghd != nil) 1298 datac <-= msghd.data; 1299 else 1300 msgtl = nil; 1301 if (err == Ehungup) { 1302 nhangups++; 1303 v.hungup = 1; 1304 } 1305 } 1306 # shutdown vwriter (may be blocked sending on errc) 1307 for (;;) alt { 1308 <- errc => 1309 ; 1310 datac <- = nil => 1311 return; 1312 } 1313} 1314 1315Viewer.new(fd: ref Sys->FD, pubscr: int, chans: Draw->Chans): string 1316{ 1317 v := ref Viewer; 1318 v.output = chan of (array of byte, chan of string); 1319 spawn vbuffer(v, fd); 1320 1321 v.imgmap = Idmap.new(); 1322 v.scrmap = Idmap.new(); 1323 v.chanmap = Idmap.new(); 1324 v.imageid = 0; 1325 v.screenid = pubscr; 1326 v.hungup = 0; 1327 v.dchans = chans; 1328 v.tmpid = 0; 1329 v.tmpR = Rect((0,0), (0,0)); 1330 1331#D := array[1+1] of byte; 1332#D[0] = byte 'D'; 1333#D[1] = byte 1; 1334#v.output <-= (D, nil); 1335 1336 reply := chan of string; 1337 # import remote public screen into our remote draw client 1338 S := array [1+4+4] of byte; 1339 S[0] = byte 'S'; 1340 put4(S, OPS_id, pubscr); 1341 put4(S, OPS_chans, chans.desc); 1342 v.output <-= (S, reply); 1343 err := <- reply; 1344 if (err != nil) { 1345 v.output <-= (nil, nil); 1346 return err; 1347 } 1348 1349 # create remote window 1350 dispid := ++v.imageid; 1351 b := array [1+4+4+1+4+1+(4*4)+(4*4)+4] of byte; 1352 b[0] = byte 'b'; 1353 put4(b, OPb_id, dispid); 1354 put4(b, OPb_screenid, pubscr); 1355 put1(b, OPb_refresh, 0); 1356 put4(b, OPb_chans, chans.desc); 1357 put1(b, OPb_repl, 0); 1358 putR(b, OPb_R, drawR); 1359 putR(b, OPb_clipR, drawR); 1360 put4(b, OPb_rrggbbaa, Draw->White); 1361 v.output <-= (b, reply); 1362 err = <- reply; 1363 if (err != nil) { 1364 v.output <-= (nil, nil); 1365 return err; 1366 } 1367 1368 # map local display image id to remote window image id 1369 v.imgmap.add(0, dispid); 1370 if (!drawchans.eq(chans)) 1371 # writepixels on this image must be chan converted 1372 v.chanmap.add(0, 1); 1373 1374 # create 'white' repl image for use as mask 1375 v.whiteid = ++v.imageid; 1376 put4(b, OPb_id, v.whiteid); 1377 put4(b, OPb_screenid, 0); 1378 put1(b, OPb_refresh, 0); 1379 put4(b, OPb_chans, (Draw->RGBA32).desc); 1380 put1(b, OPb_repl, 1); 1381 putR(b, OPb_R, Rect((0,0), (1,1))); 1382 putR(b, OPb_clipR, Rect((-16r3FFFFFFF, -16r3FFFFFFF), (16r3FFFFFFF, 16r3FFFFFFF))); 1383 put4(b, OPb_rrggbbaa, Draw->White); 1384 v.output <-= (b, reply); 1385 err = <- reply; 1386 if (err != nil) { 1387 v.output <-= (nil, nil); 1388 return err; 1389 } 1390 1391 img := images.lookup(0); 1392 key := chan of int; 1393 drawlock <- = key; 1394 v.copyimg(img, dispid); 1395 1396 O := array [1+1] of byte; 1397 O[0] = byte 'O'; 1398 O[1] = byte drawop; 1399 v.output <-= (O, nil); 1400 1401 flush := array [1] of byte; 1402 flush[0] = byte 'v'; 1403 v.output <- = (flush, nil); 1404 viewers = v :: viewers; 1405 key <-= 1; 1406 return nil; 1407} 1408 1409Viewer.process(v : self ref Viewer, req : ref Drawreq) 1410{ 1411 data := req.data; 1412 pick r := req { 1413 b => # allocate image 1414 imgid := ++v.imageid; 1415 if (r.screenid != 0) { 1416 (scrid, mapchans) := v.getscr(r.screenid, 0); 1417 put4(data, OPb_screenid, scrid); 1418 if (mapchans) { 1419 put4(data, OPb_chans, v.dchans.desc); 1420 v.chanmap.add(r.id, 1); 1421 } 1422 } 1423 v.imgmap.add(r.id, imgid); 1424 put4(data, OPb_id, imgid); 1425 1426 A => # allocate screen 1427 imgid := v.getimg(r.imageid); 1428 put4(data, OPA_fillid, v.getimg(r.fillid)); 1429 put4(data, OPA_imageid, imgid); 1430 reply := chan of string; 1431 for (i := 0; i < 25; i++) { 1432 put4(data, OPA_id, ++v.screenid); 1433 v.output <-= (data, reply); 1434 if (<-reply == nil) { 1435 v.scrmap.add(r.id, v.screenid); 1436 return; 1437 } 1438 } 1439 return; 1440 1441 c => # set clipr and repl 1442 put4(data, OPc_dstid, v.getimg(r.dstid)); 1443 1444 d => # general draw op 1445 dstid := v.imgmap.lookup(r.dstid); 1446 if (dstid == -1) { 1447 # don't do draw op as getimg() will do a writepixels 1448 v.getimg(r.dstid); 1449 return; 1450 } 1451 put4(data, OPd_maskid, v.getimg(r.maskid)); 1452 put4(data, OPd_srcid, v.getimg(r.srcid)); 1453 put4(data, OPd_dstid, dstid); 1454 1455 e => # draw ellipse 1456 dstid := v.imgmap.lookup(r.dstid); 1457 if (dstid == -1) { 1458 # don't do draw op as getimg() will do a writepixels 1459 v.getimg(r.dstid); 1460 return; 1461 } 1462 put4(data, OPe_srcid, v.getimg(r.srcid)); 1463 put4(data, OPe_dstid, dstid); 1464 1465 f => # free image 1466 id := v.imgmap.lookup(r.img.id); 1467 if (id == -1) 1468 # Viewer has never seen this image - ignore 1469 return; 1470 v.imgmap.del(r.id); 1471 # Viewers alias named images - only delete if last reference 1472 if (r.img.refc > 1) 1473 return; 1474 v.chanmap.del(r.img.id); 1475 put4(data, OPf_id, id); 1476 1477 F => # free screen 1478 id := v.scrmap.lookup(r.id); 1479 scr := screens.lookup(r.id); 1480 # image and fill are free'd separately 1481 #v.imgmap.del(scr.imageid); 1482 #v.imgmap.del(scr.fillid); 1483 if (id == -1) 1484 return; 1485 put4(data, OPF_id, id); 1486 1487 i => # convert image to font 1488 put4(data, OPi_fontid, v.getimg(r.fontid)); 1489 1490 l => # load a char into font 1491 put4(data, OPl_srcid, v.getimg(r.srcid)); 1492 put4(data, OPl_fontid, v.getimg(r.fontid)); 1493 1494 L => # draw line 1495 dstid := v.imgmap.lookup(r.dstid); 1496 if (dstid == -1) { 1497 # don't do draw op as getimg() will do a writepixels 1498 v.getimg(r.dstid); 1499 return; 1500 } 1501 put4(data, OPL_srcid, v.getimg(r.srcid)); 1502 put4(data, OPL_dstid, dstid); 1503 1504# n => # attach to named image 1505# N => # name 1506# Handled by id remapping to avoid clashes in namespace of remote viewers. 1507# If it is a name we know then the id is remapped within the images Imageset 1508# Otherwise, there is nothing we can do other than ignore all ops related to the id. 1509 1510 o => # set image origins 1511 id := v.imgmap.lookup(r.id); 1512 if (id == -1) 1513 # Viewer has never seen this image - ignore 1514 return; 1515 put4(data, OPo_id, id); 1516 1517 O => # set next compositing op 1518 ; 1519 1520 p => # draw polygon 1521 dstid := v.imgmap.lookup(r.dstid); 1522 if (dstid == -1) { 1523 # don't do draw op as getimg() will do a writepixels 1524 v.getimg(r.dstid); 1525 return; 1526 } 1527 put4(data, OPp_srcid, v.getimg(r.srcid)); 1528 put4(data, OPp_dstid, dstid); 1529 1530 s => # draw text 1531 dstid := v.imgmap.lookup(r.dstid); 1532 if (dstid == -1) { 1533 # don't do draw op as getimg() will do a writepixels 1534 v.getimg(r.dstid); 1535 return; 1536 } 1537 put4(data, OPs_fontid, v.getimg(r.fontid)); 1538 put4(data, OPs_srcid, v.getimg(r.srcid)); 1539 put4(data, OPs_dstid, dstid); 1540 1541 x => # draw text with bg 1542 dstid := v.imgmap.lookup(r.dstid); 1543 if (dstid == -1) { 1544 # don't do draw op as getimg() will do a writepixels 1545 v.getimg(r.dstid); 1546 return; 1547 } 1548 put4(data, OPx_fontid, v.getimg(r.fontid)); 1549 put4(data, OPx_srcid, v.getimg(r.srcid)); 1550 put4(data, OPx_bgid, v.getimg(r.bgid)); 1551 put4(data, OPx_dstid, dstid); 1552 1553 t => # adjust window z order 1554 for (i := 0; i < len r.ids; i++) 1555 put4(data, OPt_id + 4*i, v.getimg(r.ids[i])); 1556 1557 v => # flush updates to display 1558 ; 1559 1560 y => # write pixels 1561 id := v.imgmap.lookup(r.id); 1562 if (id == -1) { 1563 # don't do draw op as getimg() will do a writepixels 1564 v.getimg(r.id); 1565 return; 1566 } 1567 if (!drawchans.eq(v.dchans) && v.chanmap.lookup(r.id) != -1) { 1568 # chans clash 1569 img := images.lookup(r.id); 1570 # copy data as other Viewers may alter contents 1571 copy := (array [len data] of byte)[:] = data; 1572 v.chanconv(img, id, r.R, copy); 1573 return; 1574 } 1575 put4(data, OPy_id, id); 1576 1577 * => 1578 return; 1579 } 1580 # send out a copy of the data as other Viewers may alter contents 1581 copy := array [len data] of byte; 1582 copy[:] = data; 1583 v.output <-= (copy, nil); 1584} 1585 1586Viewer.getimg(v: self ref Viewer, localid: int) : int 1587{ 1588 remid := v.imgmap.lookup(localid); 1589 if (remid != -1) 1590 return remid; 1591 1592 img := images.lookup(localid); 1593 if (img.id != localid) { 1594 # attached via name, see if we have the aliased image 1595 remid = v.imgmap.lookup(img.id); 1596 if (remid != -1) { 1597 # we have it, add mapping to save us this trouble next time 1598 v.imgmap.add(localid, remid); 1599 return remid; 1600 } 1601 } 1602 # is the image a window? 1603 scrid := 0; 1604 mapchans := 0; 1605 if (img.screenid != 0) 1606 (scrid, mapchans) = v.getscr(img.screenid, img.id); 1607 1608 vid := ++v.imageid; 1609 # create the image 1610 # note: clipr for image creation has to be based on screen co-ords 1611 clipR := img.clipR.subpt(img.lorigin); 1612 clipR = clipR.addpt(img.R.min); 1613 b := array [1+4+4+1+4+1+(4*4)+(4*4)+4] of byte; 1614 b[0] = byte 'b'; 1615 put4(b, OPb_id, vid); 1616 put4(b, OPb_screenid, scrid); 1617 put1(b, OPb_refresh, 0); 1618 if (mapchans) 1619 put4(b, OPb_chans, v.dchans.desc); 1620 else 1621 put4(b, OPb_chans, img.chans.desc); 1622 put1(b, OPb_repl, img.repl); 1623 putR(b, OPb_R, img.R); 1624 putR(b, OPb_clipR, clipR); 1625 put4(b, OPb_rrggbbaa, img.rrggbbaa); 1626 v.output <-= (b, nil); 1627 1628 v.imgmap.add(img.id, vid); 1629 if (mapchans) 1630 v.chanmap.add(img.id, 1); 1631 1632 # set the origin 1633 if (img.lorigin.x != img.R.min.x || img.lorigin.y != img.R.min.y) { 1634 o := array [1+4+(2*4)+(2*4)] of byte; 1635 o[0] = byte 'o'; 1636 put4(o, OPo_id, vid); 1637 putP(o, OPo_rmin, img.lorigin); 1638 putP(o, OPo_screenrmin, img.R.min); 1639 v.output <-= (o, nil); 1640 } 1641 1642 # is the image a font? 1643 if (img.font != nil) { 1644 f := img.font; 1645 i := array [1+4+4+1] of byte; 1646 i[0] = byte 'i'; 1647 put4(i, OPi_fontid, vid); 1648 put4(i, OPi_nchars, len f.chars); 1649 put1(i, OPi_ascent, f.ascent); 1650 v.output <-= (i, nil); 1651 1652 for (index := 0; index < len f.chars; index++) { 1653 ch := f.chars[index]; 1654 if (ch == nil) 1655 continue; 1656 l := array [1+4+4+2+(4*4)+(2*4)+1+1] of byte; 1657 l[0] = byte 'l'; 1658 put4(l, OPl_fontid, vid); 1659 put4(l, OPl_srcid, v.getimg(ch.srcid)); 1660 put2(l, OPl_index, index); 1661 putR(l, OPl_R, ch.R); 1662 putP(l, OPl_P, ch.P); 1663 put1(l, OPl_left, ch.left); 1664 put1(l, OPl_width, ch.width); 1665 v.output <-= (l, nil); 1666 } 1667 } 1668 1669 # if 'dirty' then writepixels 1670 if (img.dirty) 1671 v.copyimg(img, vid); 1672 1673 return vid; 1674} 1675 1676Viewer.copyimg(v : self ref Viewer, img : ref Image, id : int) 1677{ 1678 dx := img.R.max.x - img.R.min.x; 1679 dy := img.R.max.y - img.R.min.y; 1680 srcR := Rect (img.lorigin, (img.lorigin.x + dx, img.lorigin.y + dy)); 1681 bpl := bytesperline(srcR, img.chans); 1682 rlen : con 1+4+(4*4); 1683 ystep := (Sys->ATOMICIO - rlen)/ bpl; 1684 minx := srcR.min.x; 1685 maxx := srcR.max.x; 1686 maxy := srcR.max.y; 1687 1688 chanconv := 0; 1689 if (!drawchans.eq(v.dchans) && v.chanmap.lookup(img.id) != -1) 1690 chanconv = 1; 1691 1692 for (y := img.lorigin.y; y < maxy; y += ystep) { 1693 if (y + ystep > maxy) 1694 ystep = (maxy - y); 1695 R := Draw->Rect((minx, y), (maxx, y+ystep)); 1696 r := array [rlen] of byte; 1697 r[0] = byte 'r'; 1698 put4(r, OPr_id, img.id); 1699 putR(r, OPr_R, R); 1700 if (sys->write(drawfd, r, len r) != len r) 1701 break; 1702 1703 nb := bpl * ystep; 1704 ymsg := array [1+4+(4*4)+nb] of byte; 1705 ymsg[0] = byte 'y'; 1706# put4(ymsg, OPy_id, id); 1707 putR(ymsg, OPy_R, R); 1708 n := sys->read(drawfd, ymsg[OPy_data:], nb); 1709 if (n != nb) 1710 break; 1711 if (chanconv) 1712 v.chanconv(img, id, R, ymsg); 1713 else { 1714 put4(ymsg, OPy_id, id); 1715 v.output <-= (ymsg, nil); 1716 } 1717 } 1718} 1719 1720Viewer.chanconv(v: self ref Viewer, img: ref Image, id: int, r: Rect, ymsg: array of byte) 1721{ 1722 # check origin matches and enough space in conversion image 1723 if (!(img.lorigin.eq(v.tmpR.min) && r.inrect(v.tmpR))) { 1724 # create new tmp image 1725 if (v.tmpid != 0) { 1726 f := array [1+4] of byte; 1727 f[0] = byte 'f'; 1728 put4(f, OPf_id, v.tmpid); 1729 v.output <-= (f, nil); 1730 } 1731 v.tmpR = Rect((0,0), (img.R.dx(), img.R.dy())).addpt(img.lorigin); 1732 v.tmpid = ++v.imageid; 1733 b := array [1+4+4+1+4+1+(4*4)+(4*4)+4] of byte; 1734 b[0] = byte 'b'; 1735 put4(b, OPb_id, v.tmpid); 1736 put4(b, OPb_screenid, 0); 1737 put1(b, OPb_refresh, 0); 1738 put4(b, OPb_chans, drawchans.desc); 1739 put1(b, OPb_repl, 0); 1740 putR(b, OPb_R, v.tmpR); 1741 putR(b, OPb_clipR, v.tmpR); 1742 put4(b, OPb_rrggbbaa, Draw->Nofill); 1743 v.output <-= (b, nil); 1744 } 1745 # writepixels to conversion image 1746 put4(ymsg, OPy_id, v.tmpid); 1747 v.output <-= (ymsg, nil); 1748 1749 # ensure that drawop is Draw->S 1750 if (drawop != Draw->S) { 1751 O := array [1+1] of byte; 1752 O[0] = byte 'O'; 1753 put1(O, OPO_op, Draw->S); 1754 v.output <-= (O, nil); 1755 } 1756 # blit across to real target 1757 d := array [1+4+4+4+(4*4)+(2*4)+(2*4)] of byte; 1758 d[0] = byte 'd'; 1759 put4(d, OPd_dstid, id); 1760 put4(d, OPd_srcid, v.tmpid); 1761 put4(d, OPd_maskid, v.whiteid); 1762 putR(d, OPd_R, r); 1763 putP(d, OPd_P0, r.min); 1764 putP(d, OPd_P1, r.min); 1765 v.output <-= (d, nil); 1766 1767 # restore drawop if necessary 1768 if (drawop != Draw->S) { 1769 O := array [1+1] of byte; 1770 O[0] = byte 'O'; 1771 put1(O, OPO_op, drawop); 1772 v.output <-= (O, nil); 1773 } 1774} 1775 1776# returns (rid, map) 1777# rid == remote screen id 1778# map indicates that chan mapping is required for windows on this screen 1779 1780Viewer.getscr(v : self ref Viewer, localid, winid : int) : (int, int) 1781{ 1782 remid := v.scrmap.lookup(localid); 1783 if (remid != -1) { 1784 if (drawchans.eq(v.dchans)) 1785 return (remid, 0); 1786 scr := screens.lookup(localid); 1787 if (v.chanmap.lookup(scr.imageid) == -1) 1788 return (remid, 0); 1789 return (remid, 1); 1790 } 1791 1792 scr := screens.lookup(localid); 1793 imgid := v.getimg(scr.imageid); 1794 fillid := v.getimg(scr.fillid); 1795 A := array [1+4+4+4+1] of byte; 1796 A[0] = byte 'A'; 1797 put4(A, OPA_imageid, imgid); 1798 put4(A, OPA_fillid, fillid); 1799 put1(A, OPA_public, 0); 1800 1801 reply := chan of string; 1802 for (i := 0; i < 25; i++) { 1803 put4(A, OPA_id, ++v.screenid); 1804 v.output <-= (A, reply); 1805 if (<-reply != nil) 1806 continue; 1807 v.scrmap.add(localid, v.screenid); 1808 break; 1809 } 1810 # if i == 25 then we have a problem 1811 # ... 1812 if (i == 25) { 1813# sys->print("failed to create remote screen\n"); 1814 return (0, 0); 1815 } 1816 1817 # pre-construct the windows on this screen 1818 for (ix := len scr.windows -1; ix >=0; ix--) 1819 if (scr.windows[ix] != winid) 1820 v.getimg(scr.windows[ix]); 1821 1822 if (drawchans.eq(v.dchans)) 1823 return (v.screenid, 0); 1824 if (v.chanmap.lookup(scr.imageid) == -1) 1825 return (v.screenid, 0); 1826 return (v.screenid, 1); 1827} 1828