richterm.c (18666B)
1 #include <u.h> 2 #include <libc.h> 3 #include <plumb.h> 4 #include <fcall.h> 5 #include <thread.h> 6 #include <draw.h> 7 #include <keyboard.h> 8 #include <mouse.h> 9 #include <cursor.h> 10 #include <9p.h> 11 12 #include "array.h" 13 #include "richterm.h" 14 15 int getelem(Point); 16 void insertfromcons(Array *); 17 void mouse(Mousectl *, Mouse, int *); 18 void resize(void); 19 void runcmd(void *); 20 void scroll(int, Rich *); 21 void send_interrupt(void); 22 void shutdown(void); 23 void text2runes(char *str, Array *elems); 24 25 Array *elems; 26 Array *fonts; 27 Array *richdata; 28 Channel *pidchan, *redrawc, *insertc; 29 Image *Iscrollbar, *Ilink, *Inormbg, *Iselbg, *Itext; 30 Keyboardctl *kctl; 31 Mousectl *mctl; 32 Rich rich; 33 char *cmd = "/bin/richrc"; 34 char *srvname; 35 int hostpid = -1; 36 Array *drawcache; 37 38 void mfollow(void); 39 void mpaste(void); 40 void mplumb(void); 41 void msnarf(void); 42 43 char *mitems[] = {"follow", "paste", "snarf", "plumb", nil}; 44 void (*mfunc[])(void) = {mfollow, mpaste, msnarf, mplumb, nil}; 45 46 Menu mmenu = { 47 .item = mitems, 48 .gen = nil, 49 .lasthit = 0, 50 }; 51 52 void rfollow(void *); 53 void rsnarf(void *); 54 void rplumb(void *); 55 56 char *ritems[] = {"Follow", "Snarf", "Plumb", nil}; 57 void (*rfunc[])(void *) = {rfollow, rsnarf, rplumb, nil}; 58 int rsize = sizeof(ritems) / sizeof(*ritems); 59 char * rgen(int); 60 61 Menu rmenu = { 62 .item = nil, 63 .gen = rgen, 64 .lasthit = 0, 65 }; 66 67 char * rusergen(int); 68 void ruseract(int); 69 70 Menu rusermenu = { 71 .item = nil, 72 .gen = rusergen, 73 .lasthit = 0, 74 }; 75 76 enum { 77 MM_NONE, 78 MM_SCROLLBAR, 79 MM_TEXT, 80 MM_SELECT, 81 }; 82 83 void 84 usage(void) 85 { 86 fprint(2, "usage: %s [-D] [-c command] [-s srvname] [args]\n", argv0); 87 exits("usage"); 88 } 89 90 void 91 threadmain(int argc, char **argv) 92 { 93 int rv[2], mmode; 94 Mouse mv; 95 Rune kv; 96 Array *av; 97 98 ARGBEGIN{ 99 case 'D': 100 chatty9p++; 101 break; 102 case 'c': 103 cmd = EARGF(usage()); 104 break; 105 case 's': 106 srvname = EARGF(usage()); 107 break; 108 default: 109 usage(); 110 } ARGEND 111 112 av = nil; 113 mmode = MM_NONE; 114 115 if (initdraw(0, 0, argv0) < 0) 116 sysfatal("%s: %r", argv0); 117 if ((mctl = initmouse(nil, screen)) == nil) 118 sysfatal("%s: %r", argv0); 119 if ((kctl = initkeyboard(nil)) == nil) 120 sysfatal("%s: %r", argv0); 121 122 display->locking = 1; 123 unlockdisplay(display); 124 125 Iscrollbar = allocimage( 126 display, Rect(0,0,1,1), screen->chan, 1, 0x999999FF); 127 Inormbg = allocimage( 128 display, Rect(0,0,1,1), screen->chan, 1, DWhite); 129 Iselbg = allocimage( 130 display, Rect(0,0,1,1), screen->chan, 1, 0xBBBBBBFF); 131 Ilink = allocimage( 132 display, Rect(0,0,1,1), screen->chan, 1, DBlue); 133 134 Itext = display->black; 135 136 fonts = arraycreate(sizeof(Font *), 2, nil); 137 arraygrow(fonts, 1, &font); 138 139 rich.l = mallocz(sizeof(QLock), 1); 140 141 qlock(rich.l); 142 143 rich.selmin = 0; 144 rich.selmax = 0; 145 146 qunlock(rich.l); 147 148 redrawc = chancreate(sizeof(void *), 8); 149 insertc = chancreate(sizeof(Array *), 8); 150 151 elems = arraycreate(sizeof(Elem *), 128, nil); 152 richdata = arraycreate(sizeof(char), 1024, nil); 153 drawcache = arraycreate(sizeof(DrawState), 1024, nil); 154 155 rich.selmin = 0; 156 rich.selmax = 0; 157 158 resize(); 159 draw(screen, screen->r, Inormbg, nil, ZP); 160 drawscrollbar(); 161 flushimage(display, 1); 162 163 if(rfork(RFENVG) < 0) 164 sysfatal("rfork: %r"); 165 quotefmtinstall(); 166 atexit(shutdown); 167 168 pidchan = chancreate(sizeof(int), 0); 169 proccreate(runcmd, argv, 16 * 1024); 170 hostpid = recvul(pidchan); 171 172 threadsetname("main"); 173 174 void *ov; 175 176 enum {MOUSE, RESIZE, REDRAW, INSERT, KBD, AEND}; 177 Alt alts[AEND + 1] = { 178 {mctl->c, &mv, CHANRCV}, 179 {mctl->resizec, rv, CHANRCV}, 180 {redrawc, &ov, CHANRCV}, 181 {insertc, &av, CHANRCV}, 182 {kctl->c, &kv, CHANRCV}, 183 {nil, nil, CHANEND}, 184 }; 185 186 for (;;) { 187 switch(alt(alts)) { 188 case MOUSE: 189 mouse(mctl, mv, &mmode); 190 break; 191 case RESIZE: 192 if (getwindow(display, Refnone) < 0) 193 sysfatal("resize failed: %r"); 194 resize(); 195 nbsend(redrawc, nil); 196 break; 197 case REDRAW: 198 199 while (nbrecv(redrawc, &ov) != 0); 200 201 lockdisplay(display); 202 draw(screen, rich.r, Inormbg, nil, ZP); 203 drawelems(0, elems->count); 204 drawscrollbar(); 205 flushimage(display, 1); 206 unlockdisplay(display); 207 break; 208 case INSERT: 209 insertfromcons(av); 210 nbsend(redrawc, nil); 211 break; 212 case KBD: 213 if (kv == 0x7f) shutdown(); /* delete */ 214 if (kv == 0xf00e) { /* d-pad up */ 215 scroll( 216 rich.scroll - Dy(screen->r) / 8, 217 &rich); 218 break; 219 } 220 if (kv == 0xf800) { /* d-pad down */ 221 scroll( 222 rich.scroll + Dy(screen->r) / 8, 223 &rich); 224 break; 225 } 226 if (kv == 0xf00f) { /* page up */ 227 scroll( 228 rich.scroll - Dy(screen->r) / 4, 229 &rich); 230 break; 231 } 232 if (kv == 0xf013) { /* page down */ 233 scroll( 234 rich.scroll + Dy(screen->r) / 4, 235 &rich); 236 break; 237 } 238 if (elems->count > 0) { 239 if (kv == 0x08) { /* backspace */ 240 if (rich.input < elems->count) { 241 Elem *edisc; 242 arrayget(elems, elems->count - 1, &edisc); 243 if (edisc == nil) break; 244 freeelem(edisc); 245 free(edisc); 246 arraydel(elems, elems->count - 1, 1); 247 } 248 } else { 249 Elem *enew = mallocz(sizeof(Elem), 1); 250 enew->type = TRune; 251 enew->r = kv; 252 arraygrow(elems, 1, &enew); 253 } 254 if (kv == '\n') { 255 Rune *r; 256 char *s; 257 r = getrunes(rich.input, elems->count); 258 s = smprint("%S", r); 259 260 arraygrow(richdata, 1, "."); 261 arraygrow(richdata, strlen(s), s); 262 arraygrow(richdata, 2, "n\n"); 263 264 rich.input = elems->count; 265 266 Array *msg = arraycreate(sizeof(char), strlen(s), nil); 267 arraygrow(msg, strlen(s), s); 268 nbsend(consc, &msg); 269 free(r); 270 free(s); 271 } 272 nbsend(redrawc, nil); 273 } 274 break; 275 case AEND: 276 break; 277 } 278 } 279 } 280 281 void 282 mouse(Mousectl *mc, Mouse mv, int *mmode) 283 { 284 static long selstart, selend; 285 long rstart, rend; 286 if (mv.buttons == 0) { 287 *mmode = MM_NONE; 288 return; 289 } 290 if (mv.buttons == 8) { 291 scroll( 292 rich.scroll - (mv.xy.y - rich.r.min.y), 293 &rich); 294 return; 295 } 296 if (mv.buttons == 16) { 297 scroll( 298 rich.scroll + (mv.xy.y - rich.r.min.y), 299 &rich); 300 return; 301 } 302 303 if (*mmode == MM_NONE) { 304 if (ptinrect(mv.xy, rich.rs) != 0) 305 *mmode = MM_SCROLLBAR; 306 if (ptinrect(mv.xy, rich.r) != 0) 307 *mmode = MM_TEXT; 308 } 309 310 switch (*mmode) { 311 case MM_SCROLLBAR: 312 if (mv.buttons == 1) { 313 scroll( 314 rich.scroll - (mv.xy.y - rich.r.min.y), 315 &rich); 316 } else if (mv.buttons == 2) { 317 scroll( 318 (mv.xy.y - rich.r.min.y) * 319 ((double)rich.max / Dy(rich.r)), 320 &rich); 321 } else if (mv.buttons == 4) { 322 scroll( 323 rich.scroll + (mv.xy.y - rich.r.min.y), 324 &rich); 325 } 326 break; 327 case MM_TEXT: 328 if (mv.buttons == 1) { 329 330 rstart = rich.selmin; 331 rend = rich.selmax; 332 333 selstart = getelem(mv.xy); 334 selend = selstart; 335 336 rich.selmin = selstart; 337 rich.selmax = selstart; 338 339 lockdisplay(display); 340 drawelems(rstart, rend); 341 flushimage(display, 1); 342 unlockdisplay(display); 343 344 *mmode = MM_SELECT; 345 } else if (mv.buttons == 2) { 346 int f; 347 f = menuhit(2, mc, &mmenu, nil); 348 if (f >= 0) mfunc[f](); 349 *mmode = MM_NONE; 350 } else if (mv.buttons == 4) { 351 int f; 352 int n; 353 char *link; 354 n = getelem(mv.xy); 355 link = getlink(n); 356 if (link != nil) { 357 f = menuhit(3, mc, &rmenu, nil); 358 if (f >= 0) { 359 if (f >= rsize - 1) ruseract(f - rsize + 1); 360 else rfunc[f](link); 361 } 362 } else if (menubuf->count > 0) { 363 f = menuhit(3, mc, &rusermenu, nil); 364 if (f >= 0) ruseract(f); 365 } 366 *mmode = MM_NONE; 367 } 368 break; 369 370 case MM_SELECT: 371 rend = selend; 372 if (mv.buttons == (1|2)) { 373 break; 374 } 375 if (mv.buttons == (1|4)) { 376 break; 377 } 378 selend = getelem(mv.xy); 379 if (selend == -1 ) selend = selstart; 380 381 if (selstart < selend) { 382 rich.selmin = selstart; 383 rich.selmax = selend; 384 } else { 385 rich.selmin = selend; 386 rich.selmax = selstart; 387 } 388 389 lockdisplay(display); 390 if (selend < rend) drawelems(selend, rend); 391 else drawelems(rend, selend); 392 flushimage(display, 1); 393 unlockdisplay(display); 394 395 } 396 } 397 398 Font * 399 getfont(Array *fonts, char *name) 400 { 401 int i; 402 Font *newfont, *fnt; 403 404 if (name == nil) return font; 405 if (name[0] == '\0') return font; 406 407 for (i = 0; i < fonts->count; i++){ 408 arrayget(fonts, i, &fnt); 409 if (strcmp(fnt->name, name) == 0) return fnt; 410 } 411 if ((newfont = openfont(display, name)) == nil) { 412 fprint(2, "%r\n"); 413 newfont = font; 414 } else { 415 arraygrow(fonts, 1, &newfont); 416 } 417 return newfont; 418 } 419 420 void 421 scroll(int y, Rich *r) 422 { 423 int i, delta; 424 if (y < 0) y = 0; 425 if (y > r->max) y = r->max; 426 427 delta = r->scroll - y; 428 r->scroll = y; 429 430 for (i = 0; i < drawcache->count; i++) { 431 DrawState *ds; 432 if ((ds = arrayget(drawcache, i, nil)) == nil) { 433 sysfatal("scroll: drawcache failure."); 434 } 435 ds->pos.y += delta; 436 ds->nlpos.y += delta; 437 } 438 439 nbsend(redrawc, nil); 440 } 441 442 void 443 drawscrollbar(void) 444 { 445 double D; 446 Rectangle rs; 447 D = (double)rich.max / (double)Dy(rich.r); 448 if (D != 0) { 449 rs = rectaddpt(Rect( 450 0, rich.scroll / D, 451 11, (rich.scroll + Dy(rich.r)) / D 452 ), rich.rs.min); 453 } else { 454 rs = rich.rs; 455 rs.max.x--; 456 }; 457 458 draw(screen, rich.rs, Iscrollbar, nil, ZP); 459 draw(screen, rs, Inormbg, nil, ZP); 460 } 461 462 void 463 runcmd(void *args) 464 { 465 char **argv = args; 466 char *_cmd, *syslib, *cputype; 467 468 rfork(RFNAMEG); 469 470 if ((initfs(srvname)) != 0) 471 sysfatal("initfs failed: %r"); 472 473 bind("/mnt/richterm", "/dev/", MBEFORE); 474 475 bind("/sys/lib/richterm/bin/rc/", "/bin", MAFTER); 476 cputype = getenv("cputype"); 477 syslib = smprint("/sys/lib/richterm/bin/%s/", cputype); 478 bind(syslib, "/bin", MAFTER); 479 free(cputype); 480 free(syslib); 481 482 rfork(RFFDG); 483 close(0); 484 open("/dev/cons", OREAD); 485 close(1); 486 open("/dev/cons", OWRITE); 487 dup(1, 2); 488 489 _cmd = strdup(cmd); 490 while (*argv != nil) { 491 char *old = _cmd; 492 _cmd = smprint("%s %q", _cmd, *argv); 493 free(old); 494 argv++; 495 } 496 497 procexecl(pidchan, "/bin/rc", "rcX", "-c", _cmd, nil); 498 499 sysfatal("%r"); 500 } 501 502 void 503 shutdown(void) 504 { 505 send_interrupt(); 506 threadexitsall(nil); 507 } 508 509 void 510 send_interrupt(void) 511 { 512 if(hostpid > 0) 513 postnote(PNGROUP, hostpid, "interrupt"); 514 } 515 516 void 517 resize(void) 518 { 519 drawcache->count = 0; 520 rich.rs = Rpt( 521 addpt(Pt(1,1), screen->r.min), 522 Pt(screen->r.min.x + 13, screen->r.max.y - 1) 523 ); 524 rich.r = Rpt( 525 addpt(screen->r.min, Pt(17, 0)), 526 screen->r.max 527 ); 528 } 529 530 void 531 mfollow(void) 532 { 533 Rune *r; 534 r = getrunes(rich.selmin, rich.selmax); 535 536 char *link; 537 link = smprint("%S", r); 538 539 Array *a; 540 a = arraycreate(sizeof(char), 1024, nil); 541 if (a == nil) sysfatal("rfollow: arraycreate failed: %r"); 542 arraygrow(a, 5, "link "); 543 arraygrow(a, strlen(link), link); 544 arraygrow(a, 1, "\n"); 545 546 nbsend(ctlc, &a); 547 548 free(r); 549 free(link); 550 } 551 552 void 553 mpaste(void) 554 { 555 int fd; 556 long n; 557 char buf[4096]; 558 if ((fd = open("/dev/snarf", OREAD)) > 0) { 559 while((n = read(fd, buf, sizeof(buf))) > 0) { 560 buf[n] = '\0'; 561 text2runes(buf, elems); 562 } 563 if (n < 0) fprint(2, "mpaste: %r\n"); 564 close(fd); 565 566 nbsend(redrawc, nil); 567 } 568 } 569 570 void 571 msnarf(void) 572 { 573 int fd; 574 long n; 575 Rune *r; 576 char *s; 577 if ((rich.selmin < rich.selmax) && 578 ((fd = open("/dev/snarf", OWRITE)) > 0)) { 579 r = getrunes(rich.selmin, rich.selmax); 580 s = smprint("%S", r); 581 n = write(fd, s, strlen(s)); 582 if (n < strlen(s)) fprint(2, "msnarf: %r\n"); 583 close(fd); 584 free(r); 585 free(s); 586 } 587 } 588 589 void 590 mplumb(void) 591 { 592 char buf[1024]; 593 int pd; 594 Plumbmsg m; 595 Rune *r; 596 char *s; 597 if ((pd = plumbopen("send", OWRITE)) > 0) { 598 r = getrunes(rich.selmin, rich.selmax); 599 s = smprint("%S", r); 600 m = (Plumbmsg) { 601 "richterm", 602 nil, 603 getwd(buf, sizeof(buf)), 604 "text", 605 nil, 606 strlen(s), 607 s 608 }; 609 plumbsend(pd, &m); 610 close(pd); 611 free(r); 612 free(s); 613 } 614 } 615 616 617 char * 618 rgen(int n) 619 { 620 if (n < rsize - 1) return ritems[n]; 621 else return rusergen(n - rsize + 1); 622 } 623 624 void 625 rfollow(void *v) 626 { 627 char *link = (char *)v; 628 629 Array *a; 630 a = arraycreate(sizeof(char), 1024, nil); 631 if (a == nil) sysfatal("rfollow: arraycreate failed: %r"); 632 arraygrow(a, 5, "link "); 633 arraygrow(a, strlen(link), link); 634 arraygrow(a, 1, "\n"); 635 636 nbsend(ctlc, &a); 637 } 638 639 void 640 rsnarf(void *v) 641 { 642 char *link = (char *)v; 643 644 int fd; 645 long n; 646 if ((fd = open("/dev/snarf", OWRITE)) > 0) { 647 n = write(fd, link, strlen(link)); 648 if (n < strlen(link)) fprint(2, "rsnarf: %r\n"); 649 close(fd); 650 } 651 } 652 653 void 654 rplumb(void *v) 655 { 656 char *link = (char *)v; 657 658 char buf[1024]; 659 int pd; 660 Plumbmsg m; 661 if ((pd = plumbopen("send", OWRITE)) > 0) { 662 m = (Plumbmsg) { 663 "richterm", 664 nil, 665 getwd(buf, sizeof(buf)), 666 "text", 667 nil, 668 strlen(link), 669 link 670 }; 671 plumbsend(pd, &m); 672 close(pd); 673 } 674 } 675 676 void 677 ruseract(int f) 678 { 679 Array *a; 680 char *s; 681 s = rusergen(f); 682 if (s == nil) { 683 return; 684 } 685 a = arraycreate(sizeof(char), 2048, nil); 686 arraygrow(a, 5, "menu "); 687 arraygrow(a, strlen(s), s); 688 arraygrow(a, 1, "\n"); 689 nbsend(ctlc, &a); 690 } 691 692 char * 693 rusergen(int f) 694 { 695 static char genbuf[1024]; 696 int i, k; 697 char *ps, *pe; 698 memset(genbuf, 0, sizeof(genbuf)); 699 ps = menubuf->p; 700 for (k = 0, i = 0; (k != f) && (i < menubuf->count); i++) { 701 if (menubuf->p[i] == '\n') { 702 ps = menubuf->p + i + 1; 703 k++; 704 } 705 } 706 if (k != f) return nil; 707 i++; 708 for (pe = ps; i < menubuf->count; i++, pe++) { 709 if (*pe == '\n') break; 710 } 711 if (pe == '\0') return nil; 712 if (ps == pe) return nil; 713 memcpy(genbuf, ps, pe - ps); 714 return genbuf; 715 } 716 717 void 718 text2runes(char *str, Array *elems) 719 { 720 if (str == nil) return; 721 if (*str == '\0') return; 722 723 Rune *r, *rp; 724 r = runesmprint("%s", str); 725 726 for (rp = r; *rp != L'\0'; rp++) { 727 Elem *e = mallocz(sizeof(Elem), 1); 728 e->type = TRune; 729 e->r = *rp; 730 arraygrow(elems, 1, &e); 731 } 732 free(r); 733 } 734 735 void 736 parsedata(Array *data, Array *elems) 737 { 738 Elem *e; 739 long i; 740 char *dp; 741 Array *buf = arraycreate(sizeof(char), 80, nil); 742 743 qlock(data->l); 744 745 dp = data->p; 746 747 for (i = 0; i < data->count; i++) { 748 if (dp[i] != '\n') arraygrow(buf, 1, dp + i); 749 else { 750 arraygrow(buf, 1, "\0"); 751 e = nil; 752 switch(buf->p[0]) { 753 case E_TEXT: 754 text2runes(buf->p + 1, elems); 755 break; 756 case E_NL: 757 e = malloc(sizeof(Elem)); 758 e->type = TRune; 759 e->r = L'\n'; 760 break; 761 case E_TAB: 762 e = malloc(sizeof(Elem)); 763 e->type = TRune; 764 e->r = L'\t'; 765 break; 766 case E_SPACE: 767 e = malloc(sizeof(Elem)); 768 e->type = TRune; 769 e->r = L' '; 770 break; 771 case E_LINK: 772 e = malloc(sizeof(Elem)); 773 e->type = TLink; 774 e->str = (buf->p[1] != '\0') ? 775 strdup(buf->p + 1) : nil; 776 break; 777 case E_FONT: 778 e = malloc(sizeof(Elem)); 779 e->type = TFont; 780 e->str = (buf->p[1] != '\0') ? 781 strdup(buf->p + 1) : nil; 782 break; 783 } 784 785 if (e != nil) arraygrow(elems, 1, &e); 786 buf->count = 0; 787 } 788 } 789 790 qunlock(data->l); 791 792 arrayfree(buf); 793 } 794 795 void 796 drawelems(long start, long end) 797 { 798 DrawState ds; 799 Elem *e = nil; 800 801 for (; drawcache->count > 0; drawcache->count--) { 802 if (arrayget(drawcache, drawcache->count - 1, &ds) == nil) { 803 sysfatal("drawelems: drawcache failure."); 804 } 805 if (ds.n <= start) break; 806 } 807 808 if (drawcache->count == 0) { 809 ds.pos = Pt(rich.r.min.x, rich.r.min.y - rich.scroll); 810 ds.nlpos = ds.pos; 811 ds.font = font; 812 ds.link = nil; 813 ds.n = 0; 814 arraygrow(drawcache, 1, &ds); 815 } else { 816 arrayget(drawcache, 0, &ds); 817 drawcache->count = 1; 818 } 819 820 if (end > elems->count) end = elems->count; 821 822 for (; ds.n < end; ds.n++) { 823 if (arrayget(elems, ds.n, &e) == nil) 824 sysfatal("drawelems: failed to get elem"); 825 826 switch (e->type) { 827 case TLink: 828 ds.link = e->str; 829 break; 830 case TFont: 831 ds.font = getfont(fonts, e->str); 832 break; 833 case TRune: 834 drawrune(&ds, e); 835 break; 836 } 837 } 838 if (e != nil) rich.max = ds.nlpos.y + rich.scroll - rich.r.min.y; 839 else rich.max = 0; 840 } 841 842 Point 843 drawrune(DrawState *ds, Elem *e) 844 { 845 Rectangle r = elemrect(ds, e); 846 847 Image *fg, *bg; 848 849 Rune R[2]; 850 R[0] = e->r; 851 R[1] = L'\0'; 852 853 if ((e->r == L'\t') || (e->r == L'\n')) R[0] = L' '; 854 855 fg = (ds->link != nil) ? Ilink : Itext; 856 bg = ((ds->n >= rich.selmin) && 857 (ds->n < rich.selmax)) ? Iselbg : Inormbg; 858 859 if (r.max.x > rich.r.max.x) { 860 if (rectXrect(r, rich.r) != 0) draw(screen, r, bg, nil, ZP); 861 ds->pos = ds->nlpos; 862 r = elemrect(ds, e); 863 arraygrow(drawcache, 1, ds); 864 } 865 866 if (rectXrect(r, rich.r) != 0) { 867 draw(screen, r, bg, nil, ZP); 868 runestringn(screen, ds->pos, fg, ZP, ds->font, R, 1); 869 } 870 871 ds->pos.x = r.max.x; 872 if (ds->nlpos.y < r.max.y) ds->nlpos.y = r.max.y; 873 if (ds->pos.x >= rich.r.max.x) ds->pos = ds->nlpos; 874 875 return ds->pos; 876 } 877 878 void 879 insertfromcons(Array *a) 880 { 881 int i; 882 883 if (a->count == 0) return; 884 885 qlock(a->l); 886 887 arraygrow(richdata, 1, "."); 888 889 for (i = 0; i < a->count; i++) { 890 switch (a->p[i]) { 891 case '\n': 892 arraygrow(richdata, 4, "\nn\n."); 893 break; 894 default: 895 arraygrow(richdata, 1, a->p + i); 896 } 897 } 898 899 arraygrow(richdata, 1, "\n"); 900 901 qunlock(a->l); 902 903 arrayfree(a); 904 905 Rune *r = getrunes(rich.input, elems->count); 906 907 clearelems(); 908 drawcache->count = 0; 909 910 parsedata(richdata, elems); 911 rich.input = elems->count; 912 for (i = 0; r[i] != L'\0'; i++) { 913 Elem *e = mallocz(sizeof(Elem), 1); 914 e->type = TRune; 915 e->r = r[i]; 916 arraygrow(elems, 1, &e); 917 } 918 free(r); 919 } 920 921 void 922 freeelem(Elem *e) 923 { 924 if (e == nil) sysfatal("freeelem: elem is nil!"); 925 switch(e->type) { 926 case TLink: 927 case TFont: 928 if (e->str != nil) free(e->str); 929 break; 930 } 931 } 932 933 void 934 clearelems(void) 935 { 936 int i; 937 for (i = 0; i < elems->count; i++) { 938 Elem *e; 939 arrayget(elems, i, &e); 940 freeelem(e); 941 free(e); 942 }; 943 elems->count = 0; 944 } 945 946 int 947 getelem(Point xy) 948 { 949 long i; 950 951 DrawState ds; 952 953 for (i = drawcache->count - 1; i >= 0; i--) { 954 if (arrayget(drawcache, 0, &ds) == nil) { 955 sysfatal("getelem: drawcache failure"); 956 } 957 if (ds.pos.y <= xy.y) break; 958 } 959 960 for (i = 0; i < elems->count; i++) { 961 962 if (ds.pos.y > rich.r.max.y) { 963 return -1; 964 } 965 if (ds.pos.y > xy.y) { 966 return i - 1; 967 } 968 969 Elem *e; 970 arrayget(elems, i, &e); 971 972 if (e->type == TFont) { 973 ds.font = getfont(fonts, e->str); 974 continue; 975 } 976 if (e->type == TLink) continue; 977 978 Rectangle r = elemrect(&ds, e); 979 if (ptinrect(xy, r) != 0) { 980 return i; 981 } 982 983 ds.pos.x = r.max.x; 984 if (ds.nlpos.y < r.max.y) ds.nlpos.y = r.max.y; 985 if (ds.pos.x >= rich.r.max.x) ds.pos = ds.nlpos; 986 987 } 988 return -1; 989 } 990 991 Rune * 992 getrunes(long start, long end) 993 { 994 Rune *r = malloc(sizeof(Rune) * (end - start + 1)); 995 long i, n; 996 Elem *e; 997 for (n = 0, i = start; i < end; i++) { 998 arrayget(elems, i, &e); 999 if (e->type ==TRune) { 1000 r[n] = e->r; 1001 n++; 1002 } 1003 } 1004 r[n] = L'\0'; 1005 return r; 1006 } 1007 1008 char * 1009 getlink(long n) 1010 { 1011 for (;n >= 0; n--) { 1012 Elem *e; 1013 arrayget(elems, n, &e); 1014 if (e->type == TLink) return e->str; 1015 } 1016 return nil; 1017 } 1018 1019 Rectangle 1020 elemrect(DrawState *ds, Elem *e) 1021 { 1022 Rectangle r; 1023 int tabw; 1024 Rune rbuf[2]; 1025 1026 if (e->type != TRune) return Rpt(ds->pos, ds->pos); 1027 1028 rbuf[0] = e->r; 1029 rbuf[1] = L'\0'; 1030 1031 switch(rbuf[0]) { 1032 case L'\n': 1033 r.max.x = rich.r.max.x; 1034 break; 1035 case L'\t': 1036 tabw = stringnwidth(font, "0", 1) * 4; 1037 r.max.x = rich.r.min.x + ((ds->pos.x - rich.r.min.x) / tabw + 1) * tabw; 1038 break; 1039 default: 1040 r.max.x = ds->pos.x + runestringnwidth(ds->font, rbuf, 1); 1041 } 1042 1043 r.min = ds->pos; 1044 r.max.y = ds->pos.y + ds->font->height; 1045 1046 return r; 1047 }