9fans.net/go@v0.0.7/cmd/devdraw/devdraw.go (about) 1 /* 2 * /dev/draw simulator -- handles the messages prepared by the draw library. 3 * Doesn't simulate the file system part, just the messages. 4 */ 5 6 package main 7 8 import ( 9 "bytes" 10 "encoding/binary" 11 "fmt" 12 "sync" 13 "unsafe" 14 15 "9fans.net/go/draw" 16 "9fans.net/go/draw/memdraw" 17 ) 18 19 var drawdebug int 20 21 var drawlk sync.Mutex 22 23 func draw_initdisplaymemimage(c *Client, m *memdraw.Image) { 24 c.screenimage = m 25 m.ScreenRef = 1 26 c.slot = 0 27 c.clientid = 1 28 c.op = draw.SoverD 29 } 30 31 // gfx_replacescreenimage replaces c's screen image with m. 32 // It is called by the host driver on the main host thread. 33 func gfx_replacescreenimage(c *Client, m *memdraw.Image) { 34 drawlk.Lock() 35 om := c.screenimage 36 c.screenimage = m 37 m.ScreenRef = 1 38 if om != nil { 39 om.ScreenRef-- 40 if om.ScreenRef == 0 { 41 memdraw.Free(om) 42 } 43 } 44 drawlk.Unlock() 45 gfx_mouseresized(c) 46 } 47 48 func drawrefreshscreen(l *DImage, client *Client) { 49 for l != nil && l.dscreen == nil { 50 l = l.fromname 51 } 52 if l != nil && l.dscreen.owner != client { 53 l.dscreen.owner.refreshme = 1 54 } 55 } 56 57 func drawrefresh(m *memdraw.Image, r draw.Rectangle, v interface{}) { 58 if v == nil { 59 return 60 } 61 x := v.(*Refx) 62 c := x.client 63 d := x.dimage 64 var ref *Refresh 65 for ref = c.refresh; ref != nil; ref = ref.next { 66 if ref.dimage == d { 67 draw.CombineRect(&ref.r, r) 68 return 69 } 70 } 71 ref = new(Refresh) 72 if ref != nil { 73 ref.dimage = d 74 ref.r = r 75 ref.next = c.refresh 76 c.refresh = ref 77 } 78 } 79 80 func addflush(c *Client, r draw.Rectangle) { 81 if !draw.RectClip(&r, c.screenimage.R) { 82 return 83 } 84 85 if c.flushrect.Min.X >= c.flushrect.Max.X { 86 c.flushrect = r 87 c.waste = 0 88 return 89 } 90 nbb := c.flushrect 91 draw.CombineRect(&nbb, r) 92 ar := r.Dx() * r.Dy() 93 abb := c.flushrect.Dx() * c.flushrect.Dy() 94 anbb := nbb.Dx() * nbb.Dy() 95 /* 96 * Area of new waste is area of new bb minus area of old bb, 97 * less the area of the new segment, which we assume is not waste. 98 * This could be negative, but that's OK. 99 */ 100 c.waste += anbb - abb - ar 101 if c.waste < 0 { 102 c.waste = 0 103 } 104 /* 105 * absorb if: 106 * total area is small 107 * waste is less than half total area 108 * rectangles touch 109 */ 110 if anbb <= 1024 || c.waste*2 < anbb || draw.RectXRect(c.flushrect, r) { 111 c.flushrect = nbb 112 return 113 } 114 /* emit current state */ 115 fr := c.flushrect 116 c.flushrect = r 117 c.waste = 0 118 if fr.Min.X < fr.Max.X { 119 // Unlock drawlk because rpc_flush may want to run on gfx thread, 120 // and gfx thread might be blocked on drawlk trying to install a new screen 121 // during a resize. 122 rpc_gfxdrawunlock() 123 drawlk.Unlock() 124 c.impl.rpc_flush(c, fr) 125 drawlk.Lock() 126 rpc_gfxdrawlock() 127 } 128 } 129 130 func dstflush(c *Client, dstid int, dst *memdraw.Image, r draw.Rectangle) { 131 if dstid == 0 { 132 draw.CombineRect(&c.flushrect, r) 133 return 134 } 135 /* how can this happen? -rsc, dec 12 2002 */ 136 if dst == nil { 137 // fmt.Fprintf(os.Stderr, "nil dstflush\n") 138 return 139 } 140 l := dst.Layer 141 if l == nil { 142 return 143 } 144 for { 145 if l.Screen.Image.Data != c.screenimage.Data { 146 return 147 } 148 r = r.Add(l.Delta) 149 l = l.Screen.Image.Layer 150 if l == nil { 151 break 152 } 153 } 154 addflush(c, r) 155 } 156 157 func drawflush(c *Client) { 158 r := c.flushrect 159 c.flushrect = draw.Rect(10000, 10000, -10000, -10000) 160 if r.Min.X < r.Max.X { 161 // Unlock drawlk because rpc_flush may want to run on gfx thread, 162 // and gfx thread might be blocked on drawlk trying to install a new screen 163 // during a resize. 164 rpc_gfxdrawunlock() 165 drawlk.Unlock() 166 c.impl.rpc_flush(c, r) 167 drawlk.Lock() 168 rpc_gfxdrawlock() 169 } 170 } 171 172 func drawlookupname(client *Client, str string) *DName { 173 for i := 0; i < len(client.name); i++ { 174 name := &client.name[i] 175 if name.name == str { 176 return name 177 } 178 } 179 return nil 180 } 181 182 func drawgoodname(client *Client, d *DImage) int { 183 /* if window, validate the screen's own images */ 184 if d.dscreen != nil { 185 if drawgoodname(client, d.dscreen.dimage) == 0 || drawgoodname(client, d.dscreen.dfill) == 0 { 186 return 0 187 } 188 } 189 if d.name == "" { 190 return 1 191 } 192 n := drawlookupname(client, d.name) 193 if n == nil || n.vers != d.vers { 194 return 0 195 } 196 return 1 197 } 198 199 func drawlookup(client *Client, id int, checkname int) *DImage { 200 d := client.dimage[id&HASHMASK] 201 for d != nil { 202 if d.id == id { 203 /* 204 * BUG: should error out but too hard. 205 * Return 0 instead. 206 */ 207 if checkname != 0 && drawgoodname(client, d) == 0 { 208 return nil 209 } 210 return d 211 } 212 d = d.next 213 } 214 return nil 215 } 216 217 func drawlookupdscreen(c *Client, id int) *DScreen { 218 s := c.dscreen 219 for s != nil { 220 if s.id == id { 221 return s 222 } 223 s = s.next 224 } 225 return nil 226 } 227 228 func drawlookupscreen(client *Client, id int, cs **CScreen) *DScreen { 229 s := client.cscreen 230 for s != nil { 231 if s.dscreen.id == id { 232 *cs = s 233 return s.dscreen 234 } 235 s = s.next 236 } 237 /* caller must check! */ 238 return nil 239 } 240 241 func drawinstall(client *Client, id int, i *memdraw.Image, dscreen *DScreen) *memdraw.Image { 242 d := new(DImage) 243 if d == nil { 244 return nil 245 } 246 d.id = id 247 d.ref = 1 248 d.name = "" 249 d.vers = 0 250 d.image = i 251 if i.ScreenRef != 0 { 252 i.ScreenRef++ 253 } 254 d.fchar = nil 255 d.fromname = nil 256 d.dscreen = dscreen 257 d.next = client.dimage[id&HASHMASK] 258 client.dimage[id&HASHMASK] = d 259 return i 260 } 261 262 func drawinstallscreen(client *Client, d *DScreen, id int, dimage *DImage, dfill *DImage, public int) *memdraw.Screen { 263 c := new(CScreen) 264 if dimage != nil && dimage.image != nil && dimage.image.Pix == 0 { 265 // fmt.Fprintf(os.Stderr, "bad image %p in drawinstallscreen", dimage.image) 266 panic("drawinstallscreen") 267 } 268 269 if c == nil { 270 return nil 271 } 272 if d == nil { 273 d = new(DScreen) 274 if d == nil { 275 return nil 276 } 277 s := new(memdraw.Screen) 278 if s == nil { 279 return nil 280 } 281 s.Frontmost = nil 282 s.Rearmost = nil 283 d.dimage = dimage 284 if dimage != nil { 285 s.Image = dimage.image 286 dimage.ref++ 287 } 288 d.dfill = dfill 289 if dfill != nil { 290 s.Fill = dfill.image 291 dfill.ref++ 292 } 293 d.ref = 0 294 d.id = id 295 d.screen = s 296 d.public = public 297 d.next = client.dscreen 298 d.owner = client 299 client.dscreen = d 300 } 301 c.dscreen = d 302 d.ref++ 303 c.next = client.cscreen 304 client.cscreen = c 305 return d.screen 306 } 307 308 func drawdelname(client *Client, name *DName) { 309 i := 0 310 for &client.name[i] != name { 311 i++ 312 } 313 copy(client.name[i:], client.name[i+1:]) 314 client.name = client.name[:len(client.name)-1] 315 } 316 317 func drawfreedscreen(client *Client, this *DScreen) { 318 this.ref-- 319 if this.ref < 0 { 320 // fmt.Fprintf(os.Stderr, "negative ref in drawfreedscreen\n") 321 } 322 if this.ref > 0 { 323 return 324 } 325 ds := client.dscreen 326 if ds == this { 327 client.dscreen = this.next 328 goto Found 329 } 330 for { 331 next := ds.next 332 if next == nil { 333 break 334 } /* assign = */ 335 if next == this { 336 ds.next = this.next 337 goto Found 338 } 339 ds = next 340 } 341 /* 342 * Should signal Enodrawimage, but too hard. 343 */ 344 return 345 346 Found: 347 if this.dimage != nil { 348 drawfreedimage(client, this.dimage) 349 } 350 if this.dfill != nil { 351 drawfreedimage(client, this.dfill) 352 } 353 } 354 355 func drawfreedimage(client *Client, dimage *DImage) { 356 dimage.ref-- 357 if dimage.ref < 0 { 358 // fmt.Fprintf(os.Stderr, "negative ref in drawfreedimage\n") 359 } 360 if dimage.ref > 0 { 361 return 362 } 363 364 /* any names? */ 365 for i := 0; i < len(client.name); { 366 if client.name[i].dimage == dimage { 367 drawdelname(client, &client.name[i]) 368 } else { 369 i++ 370 } 371 } 372 if dimage.fromname != nil { /* acquired by name; owned by someone else*/ 373 drawfreedimage(client, dimage.fromname) 374 return 375 } 376 ds := dimage.dscreen 377 l := dimage.image 378 dimage.dscreen = nil /* paranoia */ 379 dimage.image = nil 380 if ds != nil { 381 if l.Data == client.screenimage.Data { 382 addflush(client, l.Layer.Screenr) 383 } 384 l.Layer.Refreshptr = nil 385 if drawgoodname(client, dimage) != 0 { 386 memdraw.LDelete(l) 387 } else { 388 memdraw.LFree(l) 389 } 390 drawfreedscreen(client, ds) 391 } else { 392 if l.ScreenRef == 0 { 393 memdraw.Free(l) 394 } else { 395 l.ScreenRef-- 396 if l.ScreenRef == 0 { 397 memdraw.Free(l) 398 } 399 } 400 } 401 } 402 403 func drawuninstallscreen(client *Client, this *CScreen) { 404 cs := client.cscreen 405 if cs == this { 406 client.cscreen = this.next 407 drawfreedscreen(client, this.dscreen) 408 return 409 } 410 for { 411 next := cs.next 412 if next == nil { 413 break 414 } /* assign = */ 415 if next == this { 416 cs.next = this.next 417 drawfreedscreen(client, this.dscreen) 418 return 419 } 420 cs = next 421 } 422 } 423 424 func drawuninstall(client *Client, id int) int { 425 var d *DImage 426 for l := &client.dimage[id&HASHMASK]; ; l = &d.next { 427 d = *l 428 if d == nil { 429 break 430 } 431 if d.id == id { 432 *l = d.next 433 drawfreedimage(client, d) 434 return 0 435 } 436 } 437 return -1 438 } 439 440 func drawaddname(client *Client, di *DImage, str string) error { 441 for i := range client.name { 442 name := &client.name[i] 443 if name.name == str { 444 return fmt.Errorf("image name in use") 445 } 446 } 447 client.name = append(client.name, DName{}) 448 new := &client.name[len(client.name)-1] 449 new.name = str 450 new.dimage = di 451 new.client = client 452 client.namevers++ 453 new.vers = client.namevers 454 return nil 455 } 456 457 func drawclientop(cl *Client) draw.Op { 458 op := cl.op 459 cl.op = draw.SoverD 460 return op 461 } 462 463 func drawimage(client *Client, a []uint8) *memdraw.Image { 464 d := drawlookup(client, rd4(a), 1) 465 if d == nil { 466 return nil /* caller must check! */ 467 } 468 return d.image 469 } 470 471 func rd4(b []byte) int { 472 return int(int32(binary.LittleEndian.Uint32(b))) 473 } 474 475 func drawrectangle(r *draw.Rectangle, a []uint8) { 476 r.Min.X = rd4(a[0*4:]) 477 r.Min.Y = rd4(a[1*4:]) 478 r.Max.X = rd4(a[2*4:]) 479 r.Max.Y = rd4(a[3*4:]) 480 } 481 482 func drawpoint(p *draw.Point, a []uint8) { 483 p.X = rd4(a[0*4:]) 484 p.Y = rd4(a[1*4:]) 485 } 486 487 func drawchar(dst *memdraw.Image, p draw.Point, src *memdraw.Image, sp *draw.Point, font *DImage, index int, op draw.Op) draw.Point { 488 fc := &font.fchar[index] 489 var r draw.Rectangle 490 r.Min.X = p.X + int(fc.left) 491 r.Min.Y = p.Y - (font.ascent - int(fc.miny)) 492 r.Max.X = r.Min.X + (int(fc.maxx) - int(fc.minx)) 493 r.Max.Y = r.Min.Y + (int(fc.maxy) - int(fc.miny)) 494 var sp1 draw.Point 495 sp1.X = sp.X + int(fc.left) 496 sp1.Y = sp.Y + int(fc.miny) 497 memdraw.Draw(dst, r, src, sp1, font.image, draw.Pt(fc.minx, int(fc.miny)), op) 498 p.X += int(fc.width) 499 sp.X += int(fc.width) 500 return p 501 } 502 503 func drawcoord(p []uint8, oldx int, newx *int) []uint8 { 504 if len(p) == 0 { 505 return nil 506 } 507 b := p[0] 508 p = p[1:] 509 x := int(b & 0x7F) 510 if b&0x80 != 0 { 511 if len(p) < 1 { 512 return nil 513 } 514 x |= int(p[0]) << 7 515 x |= int(p[1]) << 15 516 p = p[2:] 517 if x&(1<<22) != 0 { 518 x |= ^0 << 23 519 } 520 } else { 521 if b&0x40 != 0 { 522 x |= ^0 << 7 523 } 524 x += oldx 525 } 526 *newx = x 527 return p 528 } 529 530 func draw_dataread(cl *Client, a []byte) (int, error) { 531 drawlk.Lock() 532 defer drawlk.Unlock() 533 534 if cl.readdata == nil { 535 return 0, fmt.Errorf("no draw data") 536 } 537 if len(a) < len(cl.readdata) { 538 return 0, fmt.Errorf("short read") 539 } 540 541 // TODO(rsc) reuse cl.readdata 542 n := copy(a, cl.readdata) 543 cl.readdata = nil 544 return n, nil 545 } 546 547 func draw_datawrite(client *Client, v []byte) (int, error) { 548 drawlk.Lock() 549 rpc_gfxdrawlock() 550 a := v 551 m := 0 552 oldn := len(v) 553 var err error 554 555 for { 556 a = a[m:] 557 if len(a) == 0 { 558 break 559 } 560 // fmt.Fprintf(os.Stderr, "msgwrite %d(%c)...", len(a), a[0]) 561 var refx *Refx 562 var reffn memdraw.Refreshfn 563 var r draw.Rectangle 564 var clipr draw.Rectangle 565 var sp draw.Point 566 var q draw.Point 567 var pp []draw.Point 568 var p draw.Point 569 var scrn *memdraw.Screen 570 var src *memdraw.Image 571 var mask *memdraw.Image 572 var lp []*memdraw.Image 573 var l *memdraw.Image 574 var i *memdraw.Image 575 var dst *memdraw.Image 576 var fc *FChar 577 var dscrn *DScreen 578 var dn *DName 579 var ll *DImage 580 var font *DImage 581 var dsrc *DImage 582 var ddst *DImage 583 var di *DImage 584 var cs *CScreen 585 var value draw.Color 586 var chan_ draw.Pix 587 var refresh uint8 588 var y int 589 var scrnid int 590 var repl int 591 var oy int 592 var ox int 593 var oesize int 594 var nw int 595 var ni int 596 var j int 597 var esize int 598 var dstid int 599 var doflush int 600 var ci int 601 var c int 602 switch a[0] { 603 /*fmt.Fprintf(os.Stderr, "bad command %d\n", a[0]); */ 604 default: 605 err = fmt.Errorf("bad draw command") 606 goto error 607 608 /* allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] 609 R[4*4] clipR[4*4] rrggbbaa[4] 610 */ 611 case 'b': 612 m = 1 + 4 + 4 + 1 + 4 + 1 + 4*4 + 4*4 + 4 613 if len(a) < m { 614 goto Eshortdraw 615 } 616 dstid = rd4(a[1:]) 617 scrnid = int(binary.LittleEndian.Uint16(a[5:])) 618 refresh = a[9] 619 chan_ = draw.Pix(binary.LittleEndian.Uint32(a[10:])) 620 repl = int(a[14]) 621 drawrectangle(&r, a[15:]) 622 drawrectangle(&clipr, a[31:]) 623 value = draw.Color(binary.LittleEndian.Uint32(a[47:])) 624 if drawlookup(client, dstid, 0) != nil { 625 goto Eimageexists 626 } 627 if scrnid != 0 { 628 dscrn = drawlookupscreen(client, scrnid, &cs) 629 if dscrn == nil { 630 goto Enodrawscreen 631 } 632 scrn = dscrn.screen 633 if repl != 0 || chan_ != scrn.Image.Pix { 634 err = fmt.Errorf("image parameters incompatibile with screen") 635 goto error 636 } 637 reffn = nil 638 switch refresh { 639 case draw.RefBackup: 640 break 641 case draw.RefNone: 642 reffn = memdraw.LNoRefresh 643 case draw.RefMesg: 644 reffn = drawrefresh 645 default: 646 err = fmt.Errorf("unknown refresh method") 647 goto error 648 } 649 l, err = memdraw.LAlloc(scrn, r, reffn, 0, value) 650 if err != nil { 651 goto Edrawmem 652 } 653 addflush(client, l.Layer.Screenr) 654 l.Clipr = clipr 655 draw.RectClip(&l.Clipr, r) 656 if drawinstall(client, dstid, l, dscrn) == nil { 657 memdraw.LDelete(l) 658 goto Edrawmem 659 } 660 dscrn.ref++ 661 if reffn != nil { 662 refx = nil 663 if funcPC(reffn) == funcPC(drawrefresh) { 664 refx = new(Refx) 665 if refx == nil { 666 if drawuninstall(client, dstid) < 0 { 667 goto Enodrawimage 668 } 669 goto Edrawmem 670 } 671 refx.client = client 672 refx.dimage = drawlookup(client, dstid, 1) 673 } 674 memdraw.LSetRefresh(l, reffn, refx) 675 } 676 continue 677 } 678 i, err = memdraw.AllocImage(r, chan_) 679 if err != nil { 680 goto Edrawmem 681 } 682 if repl != 0 { 683 i.Flags |= memdraw.Frepl 684 } 685 i.Clipr = clipr 686 if repl == 0 { 687 draw.RectClip(&i.Clipr, r) 688 } 689 if drawinstall(client, dstid, i, nil) == nil { 690 memdraw.Free(i) 691 goto Edrawmem 692 } 693 // fmt.Fprintf(os.Stderr, "ALLOC %p %v %v %x\n", i, r, i.Clipr, value) 694 memdraw.FillColor(i, value) 695 continue 696 697 /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */ 698 case 'A': 699 m = 1 + 4 + 4 + 4 + 1 700 if len(a) < m { 701 goto Eshortdraw 702 } 703 dstid = rd4(a[1:]) 704 if dstid == 0 { 705 goto Ebadarg 706 } 707 if drawlookupdscreen(client, dstid) != nil { 708 goto Escreenexists 709 } 710 ddst = drawlookup(client, rd4(a[5:]), 1) 711 dsrc = drawlookup(client, rd4(a[9:]), 1) 712 if ddst == nil || dsrc == nil { 713 goto Enodrawimage 714 } 715 if drawinstallscreen(client, nil, dstid, ddst, dsrc, int(a[13])) == nil { 716 goto Edrawmem 717 } 718 continue 719 720 /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */ 721 case 'c': 722 m = 1 + 4 + 1 + 4*4 723 if len(a) < m { 724 goto Eshortdraw 725 } 726 ddst = drawlookup(client, rd4(a[1:]), 1) 727 if ddst == nil { 728 goto Enodrawimage 729 } 730 if ddst.name != "" { 731 err = fmt.Errorf("can't change repl/clipr of shared image") 732 goto error 733 } 734 dst = ddst.image 735 if a[5] != 0 { 736 dst.Flags |= memdraw.Frepl 737 } 738 drawrectangle(&dst.Clipr, a[6:]) 739 continue 740 741 /* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */ 742 case 'd': 743 m = 1 + 4 + 4 + 4 + 4*4 + 2*4 + 2*4 744 if len(a) < m { 745 goto Eshortdraw 746 } 747 dst = drawimage(client, a[1:]) 748 dstid = rd4(a[1:]) 749 src = drawimage(client, a[5:]) 750 mask = drawimage(client, a[9:]) 751 if dst == nil || src == nil || mask == nil { 752 goto Enodrawimage 753 } 754 drawrectangle(&r, a[13:]) 755 drawpoint(&p, a[29:]) 756 drawpoint(&q, a[37:]) 757 op := drawclientop(client) 758 // fmt.Fprintf(os.Stderr, "DRAW %p %v %p %v %p %v %v\n", dst, r, src, p, mask, q, op) 759 memdraw.Draw(dst, r, src, p, mask, q, op) 760 dstflush(client, dstid, dst, r) 761 continue 762 763 /* toggle debugging: 'D' val[1] */ 764 case 'D': 765 m = 1 + 1 766 if len(a) < m { 767 goto Eshortdraw 768 } 769 drawdebug = int(a[1]) 770 continue 771 772 /* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/ 773 case 'e', 774 'E': 775 m = 1 + 4 + 4 + 2*4 + 4 + 4 + 4 + 2*4 + 2*4 776 if len(a) < m { 777 goto Eshortdraw 778 } 779 dst := drawimage(client, a[1:]) 780 dstid := rd4(a[1:]) 781 src := drawimage(client, a[5:]) 782 if dst == nil || src == nil { 783 goto Enodrawimage 784 } 785 drawpoint(&p, a[9:]) 786 e0 := rd4(a[17:]) 787 e1 := rd4(a[21:]) 788 if e0 < 0 || e1 < 0 { 789 err = fmt.Errorf("invalid ellipse semidiameter") 790 goto error 791 } 792 j := rd4(a[25:]) 793 if j < 0 { 794 err = fmt.Errorf("negative ellipse thickness") 795 goto error 796 } 797 798 drawpoint(&sp, a[29:]) 799 c = j 800 if a[0] == 'E' { 801 c = -1 802 } 803 ox := rd4(a[37:]) 804 oy := rd4(a[41:]) 805 op := drawclientop(client) 806 /* high bit indicates arc angles are present */ 807 if ox&(1<<31) != 0 { 808 if ox&(1<<30) == 0 { 809 ox &= ^(1 << 31) 810 } 811 memdraw.Arc(dst, p, e0, e1, c, src, sp, ox, oy, op) 812 } else { 813 memdraw.Ellipse(dst, p, e0, e1, c, src, sp, op) 814 } 815 dstflush(client, dstid, dst, draw.Rect(p.X-e0-j, p.Y-e1-j, p.X+e0+j+1, p.Y+e1+j+1)) 816 continue 817 818 /* free: 'f' id[4] */ 819 case 'f': 820 m = 1 + 4 821 if len(a) < m { 822 goto Eshortdraw 823 } 824 ll = drawlookup(client, rd4(a[1:]), 0) 825 if ll != nil && ll.dscreen != nil && ll.dscreen.owner != client { 826 ll.dscreen.owner.refreshme = 1 827 } 828 if drawuninstall(client, rd4(a[1:])) < 0 { 829 goto Enodrawimage 830 } 831 continue 832 833 /* free screen: 'F' id[4] */ 834 case 'F': 835 m = 1 + 4 836 if len(a) < m { 837 goto Eshortdraw 838 } 839 if drawlookupscreen(client, rd4(a[1:]), &cs) == nil { 840 goto Enodrawscreen 841 } 842 drawuninstallscreen(client, cs) 843 continue 844 845 /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */ 846 case 'i': 847 m = 1 + 4 + 4 + 1 848 if len(a) < m { 849 goto Eshortdraw 850 } 851 dstid = rd4(a[1:]) 852 if dstid == 0 { 853 err = fmt.Errorf("can't use display as font") 854 goto error 855 } 856 font = drawlookup(client, dstid, 1) 857 if font == nil { 858 goto Enodrawimage 859 } 860 if font.image.Layer != nil { 861 err = fmt.Errorf("can't use window as font") 862 goto error 863 } 864 ni = rd4(a[5:]) 865 if ni <= 0 || ni > 4096 { 866 err = fmt.Errorf("bad font size (4096 chars max)") 867 goto error 868 } 869 font.fchar = make([]FChar, ni) 870 font.ascent = int(a[9]) 871 continue 872 873 /* set image 0 to screen image */ 874 case 'J': 875 m = 1 876 if len(a) < m { 877 goto Eshortdraw 878 } 879 if drawlookup(client, 0, 0) != nil { 880 goto Eimageexists 881 } 882 drawinstall(client, 0, client.screenimage, nil) 883 client.infoid = 0 884 continue 885 886 /* get image info: 'I' */ 887 case 'I': 888 m = 1 889 if len(a) < m { 890 goto Eshortdraw 891 } 892 if client.infoid < 0 { 893 goto Enodrawimage 894 } 895 if client.infoid == 0 { 896 i = client.screenimage 897 if i == nil { 898 goto Enodrawimage 899 } 900 } else { 901 di = drawlookup(client, client.infoid, 1) 902 if di == nil { 903 goto Enodrawimage 904 } 905 i = di.image 906 } 907 repl := 0 908 if i.Flags&memdraw.Frepl != 0 { 909 repl = 1 910 } 911 client.readdata = []byte(fmt.Sprintf("%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ", 912 client.clientid, client.infoid, i.Pix.String(), repl, 913 i.R.Min.X, i.R.Min.Y, i.R.Max.X, i.R.Max.Y, 914 i.Clipr.Min.X, i.Clipr.Min.Y, i.Clipr.Max.X, i.Clipr.Max.Y)) 915 client.infoid = -1 916 continue 917 918 /* query: 'Q' n[1] queryspec[n] */ 919 case 'q': 920 if len(a) < 2 { 921 goto Eshortdraw 922 } 923 m = 1 + 1 + int(a[1]) 924 if len(a) < m { 925 goto Eshortdraw 926 } 927 var buf bytes.Buffer 928 for c = 0; c < int(a[1]); c++ { 929 switch a[2+c] { 930 default: 931 err = fmt.Errorf("unknown query") 932 goto error 933 case 'd': /* dpi */ 934 if client.forcedpi != 0 { 935 fmt.Fprintf(&buf, "%11d ", client.forcedpi) 936 } else { 937 fmt.Fprintf(&buf, "%11d ", client.displaydpi) 938 } 939 } 940 } 941 client.readdata = buf.Bytes() 942 continue 943 944 /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */ 945 case 'l': 946 m = 1 + 4 + 4 + 2 + 4*4 + 2*4 + 1 + 1 947 if len(a) < m { 948 goto Eshortdraw 949 } 950 font = drawlookup(client, rd4(a[1:]), 1) 951 if font == nil { 952 goto Enodrawimage 953 } 954 if len(font.fchar) == 0 { 955 goto Enotfont 956 } 957 src = drawimage(client, a[5:]) 958 if src == nil { 959 goto Enodrawimage 960 } 961 ci = int(binary.LittleEndian.Uint16(a[9:])) 962 if ci >= len(font.fchar) { 963 goto Eindex 964 } 965 drawrectangle(&r, a[11:]) 966 drawpoint(&p, a[27:]) 967 memdraw.Draw(font.image, r, src, p, memdraw.Opaque, p, draw.S) 968 fc = &font.fchar[ci] 969 fc.minx = r.Min.X 970 fc.maxx = r.Max.X 971 fc.miny = uint8(r.Min.Y) 972 fc.maxy = uint8(r.Max.Y) 973 fc.left = int8(a[35]) 974 fc.width = a[36] 975 continue 976 977 /* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */ 978 case 'L': 979 m = 1 + 4 + 2*4 + 2*4 + 4 + 4 + 4 + 4 + 2*4 980 if len(a) < m { 981 goto Eshortdraw 982 } 983 dst = drawimage(client, a[1:]) 984 dstid = rd4(a[1:]) 985 drawpoint(&p, a[5:]) 986 drawpoint(&q, a[13:]) 987 e0 := draw.End(rd4(a[21:])) 988 e1 := draw.End(rd4(a[25:])) 989 j = rd4(a[29:]) 990 if j < 0 { 991 err = fmt.Errorf("negative line width") 992 goto error 993 } 994 src = drawimage(client, a[33:]) 995 if dst == nil || src == nil { 996 goto Enodrawimage 997 } 998 drawpoint(&sp, a[37:]) 999 op := drawclientop(client) 1000 memdraw.Line(dst, p, q, e0, e1, j, src, sp, op) 1001 /* avoid memlinebbox if possible */ 1002 if dstid == 0 || dst.Layer != nil { 1003 /* BUG: this is terribly inefficient: update maximal containing rect*/ 1004 r = memdraw.LineBBox(p, q, e0, e1, j) 1005 dstflush(client, dstid, dst, r.Inset(-(1 + 1 + j))) 1006 } 1007 continue 1008 1009 /* create image mask: 'm' newid[4] id[4] */ 1010 /* 1011 * 1012 case 'm': 1013 m = 4+4; 1014 if(len(a) < m) 1015 goto Eshortdraw; 1016 break; 1017 * 1018 */ 1019 1020 /* attach to a named image: 'n' dstid[4] j[1] name[j] */ 1021 case 'n': 1022 m = 1 + 4 + 1 1023 if len(a) < m { 1024 goto Eshortdraw 1025 } 1026 j = int(a[5]) 1027 if j == 0 { /* give me a non-empty name please */ 1028 goto Eshortdraw 1029 } 1030 m += j 1031 if len(a) < m { 1032 goto Eshortdraw 1033 } 1034 dstid = rd4(a[1:]) 1035 if drawlookup(client, dstid, 0) != nil { 1036 goto Eimageexists 1037 } 1038 s := string(a[6 : 6+j]) 1039 dn = drawlookupname(client, s) 1040 if dn == nil { 1041 goto Enoname 1042 } 1043 if drawinstall(client, dstid, dn.dimage.image, nil) == nil { 1044 goto Edrawmem 1045 } 1046 di = drawlookup(client, dstid, 0) 1047 if di == nil { 1048 goto Eoldname 1049 } 1050 di.vers = dn.vers 1051 di.name = s 1052 di.fromname = dn.dimage 1053 di.fromname.ref++ 1054 client.infoid = dstid 1055 continue 1056 1057 /* name an image: 'N' dstid[4] in[1] j[1] name[j] */ 1058 case 'N': 1059 m = 1 + 4 + 1 + 1 1060 if len(a) < m { 1061 goto Eshortdraw 1062 } 1063 c = int(a[5]) 1064 j = int(a[6]) 1065 if j == 0 { /* give me a non-empty name please */ 1066 goto Eshortdraw 1067 } 1068 m += j 1069 if len(a) < m { 1070 goto Eshortdraw 1071 } 1072 di = drawlookup(client, rd4(a[1:]), 0) 1073 if di == nil { 1074 goto Enodrawimage 1075 } 1076 if di.name != "" { 1077 goto Enamed 1078 } 1079 if c != 0 { 1080 s := string(a[7 : 7+j]) 1081 if err = drawaddname(client, di, s); err != nil { 1082 goto error 1083 } 1084 dn = drawlookupname(client, s) 1085 if dn == nil { 1086 goto Enoname 1087 } 1088 if dn.dimage != di { 1089 goto Ewrongname 1090 } 1091 drawdelname(client, dn) 1092 } 1093 continue 1094 1095 /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */ 1096 case 'o': 1097 m = 1 + 4 + 2*4 + 2*4 1098 if len(a) < m { 1099 goto Eshortdraw 1100 } 1101 dst = drawimage(client, a[1:]) 1102 if dst == nil { 1103 goto Enodrawimage 1104 } 1105 if dst.Layer != nil { 1106 drawpoint(&p, a[5:]) 1107 drawpoint(&q, a[13:]) 1108 r = dst.Layer.Screenr 1109 ni, err = memdraw.LOrigin(dst, p, q) 1110 if err != nil { 1111 goto error 1112 } 1113 if ni > 0 { 1114 addflush(client, r) 1115 addflush(client, dst.Layer.Screenr) 1116 ll = drawlookup(client, rd4(a[1:]), 1) 1117 drawrefreshscreen(ll, client) 1118 } 1119 } 1120 continue 1121 1122 /* set compositing operator for next draw operation: 'O' op */ 1123 case 'O': 1124 m = 1 + 1 1125 if len(a) < m { 1126 goto Eshortdraw 1127 } 1128 client.op = draw.Op(a[1]) 1129 continue 1130 1131 /* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */ 1132 /* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */ 1133 case 'p', 1134 'P': 1135 m = 1 + 4 + 2 + 4 + 4 + 4 + 4 + 2*4 1136 if len(a) < m { 1137 goto Eshortdraw 1138 } 1139 dstid = rd4(a[1:]) 1140 dst = drawimage(client, a[1:]) 1141 ni = int(binary.LittleEndian.Uint16(a[5:])) 1142 if ni < 0 { 1143 err = fmt.Errorf("negative cout in polygon") 1144 goto error 1145 } 1146 e0 := draw.End(rd4(a[7:])) 1147 e1 := draw.End(rd4(a[11:])) 1148 j = 0 1149 if a[0] == 'p' { 1150 j = rd4(a[15:]) 1151 if j < 0 { 1152 err = fmt.Errorf("negative polygon line width") 1153 goto error 1154 } 1155 } 1156 src = drawimage(client, a[19:]) 1157 if dst == nil || src == nil { 1158 goto Enodrawimage 1159 } 1160 drawpoint(&sp, a[23:]) 1161 drawpoint(&p, a[31:]) 1162 ni++ 1163 pp = make([]draw.Point, ni) 1164 doflush = 0 1165 if dstid == 0 || (dst.Layer != nil && dst.Layer.Screen.Image.Data == client.screenimage.Data) { 1166 doflush = 1 /* simplify test in loop */ 1167 } 1168 oy = 0 1169 ox = oy 1170 esize = 0 1171 u := a[m:] 1172 for y = 0; y < ni; y++ { 1173 q = p 1174 oesize = esize 1175 u = drawcoord(u, ox, &p.X) 1176 if u == nil { 1177 goto Eshortdraw 1178 } 1179 u = drawcoord(u, oy, &p.Y) 1180 if u == nil { 1181 goto Eshortdraw 1182 } 1183 ox = p.X 1184 oy = p.Y 1185 if doflush != 0 { 1186 esize = j 1187 if a[0] == 'p' { 1188 if y == 0 { 1189 c = memdraw.LineEndSize(e0) 1190 if c > esize { 1191 esize = c 1192 } 1193 } 1194 if y == ni-1 { 1195 c = memdraw.LineEndSize(e1) 1196 if c > esize { 1197 esize = c 1198 } 1199 } 1200 } 1201 if a[0] == 'P' && e0 != 1 && e0 != ^0 { 1202 r = dst.Clipr 1203 } else if y > 0 { 1204 r = draw.Rect(q.X-oesize, q.Y-oesize, q.X+oesize+1, q.Y+oesize+1) 1205 draw.CombineRect(&r, draw.Rect(p.X-esize, p.Y-esize, p.X+esize+1, p.Y+esize+1)) 1206 } 1207 if draw.RectClip(&r, dst.Clipr) { /* should perhaps be an arg to dstflush */ 1208 dstflush(client, dstid, dst, r) 1209 } 1210 } 1211 pp[y] = p 1212 } 1213 if y == 1 { 1214 dstflush(client, dstid, dst, draw.Rect(p.X-esize, p.Y-esize, p.X+esize+1, p.Y+esize+1)) 1215 } 1216 op := drawclientop(client) 1217 if a[0] == 'p' { 1218 memdraw.Poly(dst, pp, e0, e1, j, src, sp, op) 1219 } else { 1220 memdraw.FillPoly(dst, pp, int(e0), src, sp, op) 1221 } 1222 m = len(a) - len(u) 1223 continue 1224 1225 /* read: 'r' id[4] R[4*4] */ 1226 case 'r': 1227 m = 1 + 4 + 4*4 1228 if len(a) < m { 1229 goto Eshortdraw 1230 } 1231 i = drawimage(client, a[1:]) 1232 if i == nil { 1233 goto Enodrawimage 1234 } 1235 drawrectangle(&r, a[5:]) 1236 if !draw.RectInRect(r, i.R) { 1237 goto Ereadoutside 1238 } 1239 c = draw.BytesPerLine(r, i.Depth) 1240 c *= r.Dy() 1241 client.readdata = make([]byte, c) 1242 n, e := memdraw.Unload(i, r, client.readdata) 1243 if e != nil { 1244 client.readdata = nil 1245 err = fmt.Errorf("bad readimage call") 1246 goto error 1247 } 1248 client.readdata = client.readdata[:n] 1249 continue 1250 1251 /* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */ 1252 /* 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]) */ 1253 case 's', 1254 'x': 1255 m = 1 + 4 + 4 + 4 + 2*4 + 4*4 + 2*4 + 2 1256 if a[0] == 'x' { 1257 m += 4 + 2*4 1258 } 1259 if len(a) < m { 1260 goto Eshortdraw 1261 } 1262 1263 dst = drawimage(client, a[1:]) 1264 dstid = rd4(a[1:]) 1265 src = drawimage(client, a[5:]) 1266 if dst == nil || src == nil { 1267 goto Enodrawimage 1268 } 1269 font = drawlookup(client, rd4(a[9:]), 1) 1270 if font == nil { 1271 goto Enodrawimage 1272 } 1273 if len(font.fchar) == 0 { 1274 goto Enotfont 1275 } 1276 drawpoint(&p, a[13:]) 1277 drawrectangle(&r, a[21:]) 1278 drawpoint(&sp, a[37:]) 1279 ni = int(binary.LittleEndian.Uint16(a[45:])) 1280 u := a[m:] 1281 m += ni * 2 1282 if len(a) < m { 1283 goto Eshortdraw 1284 } 1285 clipr = dst.Clipr 1286 dst.Clipr = r 1287 op := drawclientop(client) 1288 if a[0] == 'x' { 1289 /* paint background */ 1290 l = drawimage(client, a[47:]) 1291 if l == nil { 1292 goto Enodrawimage 1293 } 1294 drawpoint(&q, a[51:]) 1295 r.Min.X = p.X 1296 r.Min.Y = p.Y - font.ascent 1297 r.Max.X = p.X 1298 r.Max.Y = r.Min.Y + font.image.R.Dy() 1299 u := u // local copy 1300 j = ni 1301 for { 1302 j-- 1303 if j < 0 { 1304 break 1305 } 1306 ci = int(binary.LittleEndian.Uint16(u)) 1307 if ci < 0 || ci >= len(font.fchar) { 1308 dst.Clipr = clipr 1309 goto Eindex 1310 } 1311 r.Max.X += int(font.fchar[ci].width) 1312 u = u[2:] 1313 } 1314 memdraw.Draw(dst, r, l, q, memdraw.Opaque, draw.ZP, op) 1315 } 1316 q = p 1317 for { 1318 ni-- 1319 if ni < 0 { 1320 break 1321 } 1322 ci = int(binary.LittleEndian.Uint16(u)) 1323 if ci < 0 || ci >= len(font.fchar) { 1324 dst.Clipr = clipr 1325 goto Eindex 1326 } 1327 q = drawchar(dst, q, src, &sp, font, ci, op) 1328 u = u[2:] 1329 } 1330 dst.Clipr = clipr 1331 p.Y -= font.ascent 1332 dstflush(client, dstid, dst, draw.Rect(p.X, p.Y, q.X, p.Y+font.image.R.Dy())) 1333 continue 1334 1335 /* use public screen: 'S' id[4] chan[4] */ 1336 case 'S': 1337 m = 1 + 4 + 4 1338 if len(a) < m { 1339 goto Eshortdraw 1340 } 1341 dstid = rd4(a[1:]) 1342 if dstid == 0 { 1343 goto Ebadarg 1344 } 1345 dscrn = drawlookupdscreen(client, dstid) 1346 if dscrn == nil || (dscrn.public == 0 && dscrn.owner != client) { 1347 goto Enodrawscreen 1348 } 1349 if dscrn.screen.Image.Pix != draw.Pix(binary.LittleEndian.Uint32(a[5:])) { 1350 err = fmt.Errorf("inconsistent chan") 1351 goto error 1352 } 1353 if drawinstallscreen(client, dscrn, 0, nil, nil, 0) == nil { 1354 goto Edrawmem 1355 } 1356 continue 1357 1358 /* top or bottom windows: 't' top[1] nw[2] n*id[4] */ 1359 case 't': 1360 m = 1 + 1 + 2 1361 if len(a) < m { 1362 goto Eshortdraw 1363 } 1364 nw = int(binary.LittleEndian.Uint16(a[2:])) 1365 if nw < 0 { 1366 goto Ebadarg 1367 } 1368 if nw == 0 { 1369 continue 1370 } 1371 m += nw * 4 1372 if len(a) < m { 1373 goto Eshortdraw 1374 } 1375 lp = make([]*memdraw.Image, nw) 1376 for j = 0; j < nw; j++ { 1377 lp[j] = drawimage(client, a[1+1+2+j*4:]) 1378 if lp[j] == nil { 1379 goto Enodrawimage 1380 } 1381 } 1382 if lp[0].Layer == nil { 1383 err = fmt.Errorf("images are not windows") 1384 goto error 1385 } 1386 for j = 1; j < nw; j++ { 1387 if lp[j].Layer.Screen != lp[0].Layer.Screen { 1388 err = fmt.Errorf("images not on same screen") 1389 goto error 1390 } 1391 } 1392 if a[1] != 0 { 1393 memdraw.LToFrontN(lp, nw) 1394 } else { 1395 memdraw.LToRearN(lp, nw) 1396 } 1397 if lp[0].Layer.Screen.Image.Data == client.screenimage.Data { 1398 for j = 0; j < nw; j++ { 1399 addflush(client, lp[j].Layer.Screenr) 1400 } 1401 } 1402 ll = drawlookup(client, rd4(a[1+1+2:]), 1) 1403 drawrefreshscreen(ll, client) 1404 continue 1405 1406 /* visible: 'v' */ 1407 case 'v': 1408 m = 1 1409 drawflush(client) 1410 continue 1411 1412 /* write: 'y' id[4] R[4*4] data[x*1] */ 1413 /* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */ 1414 case 'y', 1415 'Y': 1416 m = 1 + 4 + 4*4 1417 if len(a) < m { 1418 goto Eshortdraw 1419 } 1420 dstid = rd4(a[1:]) 1421 dst = drawimage(client, a[1:]) 1422 if dst == nil { 1423 goto Enodrawimage 1424 } 1425 drawrectangle(&r, a[5:]) 1426 if !draw.RectInRect(r, dst.R) { 1427 goto Ewriteoutside 1428 } 1429 y, err = memdraw.Load(dst, r, a[m:], a[0] == 'Y') 1430 if err != nil { 1431 err = fmt.Errorf("bad writeimage call") 1432 goto error 1433 } 1434 dstflush(client, dstid, dst, r) 1435 m += y 1436 continue 1437 } 1438 } 1439 rpc_gfxdrawunlock() 1440 drawlk.Unlock() 1441 return oldn - len(a), nil 1442 1443 Enodrawimage: 1444 err = fmt.Errorf("unknown id for draw image") 1445 goto error 1446 Enodrawscreen: 1447 err = fmt.Errorf("unknown id for draw screen") 1448 goto error 1449 Eshortdraw: 1450 err = fmt.Errorf("short draw message") 1451 goto error 1452 /* 1453 Eshortread: 1454 err = fmt.Errorf("draw read too short"); 1455 goto error; 1456 */ 1457 Eimageexists: 1458 err = fmt.Errorf("image id in use") 1459 goto error 1460 Escreenexists: 1461 err = fmt.Errorf("screen id in use") 1462 goto error 1463 Edrawmem: 1464 err = fmt.Errorf("image memory allocation failed") 1465 goto error 1466 Ereadoutside: 1467 err = fmt.Errorf("readimage outside image") 1468 goto error 1469 Ewriteoutside: 1470 err = fmt.Errorf("writeimage outside image") 1471 goto error 1472 Enotfont: 1473 err = fmt.Errorf("image not a font") 1474 goto error 1475 Eindex: 1476 err = fmt.Errorf("character index out of range") 1477 goto error 1478 /* 1479 Enoclient: 1480 err = fmt.Errorf("no such draw client"); 1481 goto error; 1482 Edepth: 1483 err = fmt.Errorf("image has bad depth"); 1484 goto error; 1485 Enameused: 1486 err = fmt.Errorf("image name in use"); 1487 goto error; 1488 */ 1489 Enoname: 1490 err = fmt.Errorf("no image with that name") 1491 goto error 1492 Eoldname: 1493 err = fmt.Errorf("named image no longer valid") 1494 goto error 1495 Enamed: 1496 err = fmt.Errorf("image already has name") 1497 goto error 1498 Ewrongname: 1499 err = fmt.Errorf("wrong name for image") 1500 goto error 1501 Ebadarg: 1502 err = fmt.Errorf("bad argument in draw message") 1503 goto error 1504 1505 error: 1506 rpc_gfxdrawunlock() 1507 drawlk.Unlock() 1508 return 0, err 1509 } 1510 1511 type eface struct { 1512 _type unsafe.Pointer 1513 data unsafe.Pointer 1514 } 1515 1516 func funcPC(f interface{}) uintptr { 1517 return *(*uintptr)(efaceOf(&f).data) 1518 } 1519 func efaceOf(ep *interface{}) *eface { 1520 return (*eface)(unsafe.Pointer(ep)) 1521 }