1 /* 2 * the actual viewer that handles screen stuff 3 */ 4 5 #include <u.h> 6 #include <libc.h> 7 #include <draw.h> 8 #include <cursor.h> 9 #include <event.h> 10 #include <bio.h> 11 #include <plumb.h> 12 #include <ctype.h> 13 #include <keyboard.h> 14 #include "page.h" 15 16 Document *doc; 17 Image *im; 18 int page; 19 int upside = 0; 20 int showbottom = 0; /* on the next showpage, move the image so the bottom is visible. */ 21 22 Rectangle ulrange; /* the upper left corner of the image must be in this rectangle */ 23 Point ul; /* the upper left corner of the image is at this point on the screen */ 24 25 Point pclip(Point, Rectangle); 26 Rectangle mkrange(Rectangle screenr, Rectangle imr); 27 void redraw(Image*); 28 29 Cursor reading={ 30 {-1, -1}, 31 {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, 32 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0, 33 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0, 34 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, }, 35 {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00, 36 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0, 37 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40, 38 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, } 39 }; 40 41 Cursor query = { 42 {-7,-7}, 43 {0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 44 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8, 45 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0, 46 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, }, 47 {0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, 48 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 49 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80, 50 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, } 51 }; 52 53 enum { 54 Left = 1, 55 Middle = 2, 56 Right = 4, 57 58 RMenu = 3, 59 }; 60 61 void 62 unhide(void) 63 { 64 static int wctl = -1; 65 66 if(wctl < 0) 67 wctl = open("/dev/wctl", OWRITE); 68 if(wctl < 0) 69 return; 70 71 write(wctl, "unhide", 6); 72 } 73 74 int 75 max(int a, int b) 76 { 77 return a > b ? a : b; 78 } 79 80 int 81 min(int a, int b) 82 { 83 return a < b ? a : b; 84 } 85 86 87 char* 88 menugen(int n) 89 { 90 static char menustr[32]; 91 char *p; 92 int len; 93 94 if(n == doc->npage) 95 return "exit"; 96 if(n > doc->npage) 97 return nil; 98 99 if(reverse) 100 n = doc->npage-1-n; 101 102 p = doc->pagename(doc, n); 103 len = (sizeof menustr)-2; 104 105 if(strlen(p) > len && strrchr(p, '/')) 106 p = strrchr(p, '/')+1; 107 if(strlen(p) > len) 108 p = p+strlen(p)-len; 109 110 strcpy(menustr+1, p); 111 if(page == n) 112 menustr[0] = '>'; 113 else 114 menustr[0] = ' '; 115 return menustr; 116 } 117 118 void 119 showpage(int page, Menu *m) 120 { 121 if(doc->fwdonly) 122 m->lasthit = 0; /* this page */ 123 else 124 m->lasthit = reverse ? doc->npage-1-page : page; 125 126 esetcursor(&reading); 127 freeimage(im); 128 if((page < 0 || page >= doc->npage) && !doc->fwdonly){ 129 im = nil; 130 return; 131 } 132 im = doc->drawpage(doc, page); 133 if(im == nil) { 134 if(doc->fwdonly) /* this is how we know we're out of pages */ 135 wexits(0); 136 137 im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack); 138 if(im == nil) { 139 fprint(2, "out of memory: %r\n"); 140 wexits("memory"); 141 } 142 string(im, ZP, display->white, ZP, display->defaultfont, "?"); 143 }else if(resizing){ 144 resize(Dx(im->r), Dy(im->r)); 145 } 146 if(upside) 147 rot180(im); 148 149 esetcursor(nil); 150 if(showbottom){ 151 ul.y = screen->r.max.y - Dy(im->r); 152 showbottom = 0; 153 } 154 155 redraw(screen); 156 flushimage(display, 1); 157 } 158 159 char* 160 writebitmap(void) 161 { 162 char basename[64]; 163 char name[64+30]; 164 static char result[200]; 165 char *p, *q; 166 int fd; 167 168 if(im == nil) 169 return "no image"; 170 171 memset(basename, 0, sizeof basename); 172 if(doc->docname) 173 strncpy(basename, doc->docname, sizeof(basename)-1); 174 else if((p = menugen(page)) && p[0] != '\0') 175 strncpy(basename, p+1, sizeof(basename)-1); 176 177 if(basename[0]) { 178 if(q = strrchr(basename, '/')) 179 q++; 180 else 181 q = basename; 182 if(p = strchr(q, '.')) 183 *p = 0; 184 185 memset(name, 0, sizeof name); 186 snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1); 187 if(access(name, 0) >= 0) { 188 strcat(name, "XXXX"); 189 mktemp(name); 190 } 191 if(access(name, 0) >= 0) 192 return "couldn't think of a name for bitmap"; 193 } else { 194 strcpy(name, "bitXXXX"); 195 mktemp(name); 196 if(access(name, 0) >= 0) 197 return "couldn't think of a name for bitmap"; 198 } 199 200 if((fd = create(name, OWRITE, 0666)) < 0) { 201 snprint(result, sizeof result, "cannot create %s: %r", name); 202 return result; 203 } 204 205 if(writeimage(fd, im, 0) < 0) { 206 snprint(result, sizeof result, "cannot writeimage: %r"); 207 close(fd); 208 return result; 209 } 210 close(fd); 211 212 snprint(result, sizeof result, "wrote %s", name); 213 return result; 214 } 215 216 static void translate(Point); 217 218 static int 219 showdata(Plumbmsg *msg) 220 { 221 char *s; 222 223 s = plumblookup(msg->attr, "action"); 224 return s && strcmp(s, "showdata")==0; 225 } 226 227 void 228 viewer(Document *dd) 229 { 230 int i, fd, n, oldpage; 231 int nxt; 232 Menu menu; 233 Mouse m; 234 Event e; 235 Point dxy, oxy, xy0; 236 Rectangle r; 237 char *fwditems[] = { "this page", "next page", "exit", 0 }; 238 char *s; 239 enum { Eplumb = 4 }; 240 Plumbmsg *pm; 241 242 doc = dd; /* save global for menuhit */ 243 ul = screen->r.min; 244 einit(Emouse|Ekeyboard); 245 if(doc->addpage != nil) 246 eplumb(Eplumb, "image"); 247 248 esetcursor(&reading); 249 r.min = ZP; 250 251 /* 252 * im is a global pointer to the current image. 253 * eventually, i think we will have a layer between 254 * the display routines and the ps/pdf/whatever routines 255 * to perhaps cache and handle images of different 256 * sizes, etc. 257 */ 258 im = 0; 259 page = reverse ? doc->npage-1 : 0; 260 261 if(doc->fwdonly) { 262 menu.item = fwditems; 263 menu.gen = 0; 264 menu.lasthit = 0; 265 } else { 266 menu.item = 0; 267 menu.gen = menugen; 268 menu.lasthit = 0; 269 } 270 271 showpage(page, &menu); 272 esetcursor(nil); 273 274 nxt = 0; 275 for(;;) { 276 /* 277 * throughout, if doc->fwdonly is set, we restrict the functionality 278 * a fair amount. we don't care about doc->npage anymore, and 279 * all that can be done is select the next page. 280 */ 281 switch(eread(Emouse|Ekeyboard|Eplumb, &e)){ 282 case Ekeyboard: 283 if(e.kbdc <= 0xFF && isdigit(e.kbdc)) { 284 nxt = nxt*10+e.kbdc-'0'; 285 break; 286 } else if(e.kbdc != '\n') 287 nxt = 0; 288 switch(e.kbdc) { 289 case 'r': /* reverse page order */ 290 if(doc->fwdonly) 291 break; 292 reverse = !reverse; 293 menu.lasthit = doc->npage-1-menu.lasthit; 294 295 /* 296 * the theory is that if we are reversing the 297 * document order and are on the first or last 298 * page then we're just starting and really want 299 * to view the other end. maybe the if 300 * should be dropped and this should happen always. 301 */ 302 if(page == 0 || page == doc->npage-1) { 303 page = doc->npage-1-page; 304 showpage(page, &menu); 305 } 306 break; 307 case 'w': /* write bitmap of current screen */ 308 esetcursor(&reading); 309 s = writebitmap(); 310 if(s) 311 string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP, 312 display->defaultfont, s); 313 esetcursor(nil); 314 flushimage(display, 1); 315 break; 316 case 'd': /* remove image from working set */ 317 if(doc->rmpage && page < doc->npage) { 318 if(doc->rmpage(doc, page) >= 0) { 319 if(doc->npage < 0) 320 wexits(0); 321 if(page >= doc->npage) 322 page = doc->npage-1; 323 showpage(page, &menu); 324 } 325 } 326 break; 327 case 'q': 328 case 0x04: /* ctrl-d */ 329 wexits(0); 330 case 'u': 331 if(im==nil) 332 break; 333 esetcursor(&reading); 334 rot180(im); 335 esetcursor(nil); 336 upside = !upside; 337 redraw(screen); 338 flushimage(display, 1); 339 break; 340 case '-': 341 case '\b': 342 case Kleft: 343 if(page > 0 && !doc->fwdonly) { 344 --page; 345 showpage(page, &menu); 346 } 347 break; 348 case '\n': 349 if(nxt) { 350 nxt--; 351 if(nxt >= 0 && nxt < doc->npage && !doc->fwdonly) 352 showpage(page=nxt, &menu); 353 nxt = 0; 354 break; 355 } 356 goto Gotonext; 357 case Kright: 358 case ' ': 359 Gotonext: 360 if(doc->npage && ++page >= doc->npage && !doc->fwdonly) 361 wexits(0); 362 showpage(page, &menu); 363 break; 364 365 /* 366 * The upper y coordinate of the image is at ul.y in screen->r. 367 * Panning up means moving the upper left corner down. If the 368 * upper left corner is currently visible, we need to go back a page. 369 */ 370 case Kup: 371 if(screen->r.min.y <= ul.y && ul.y < screen->r.max.y){ 372 if(page > 0 && !doc->fwdonly){ 373 --page; 374 showbottom = 1; 375 showpage(page, &menu); 376 } 377 } else { 378 i = Dy(screen->r)/2; 379 if(i > 10) 380 i -= 10; 381 if(i+ul.y > screen->r.min.y) 382 i = screen->r.min.y - ul.y; 383 translate(Pt(0, i)); 384 } 385 break; 386 387 /* 388 * If the lower y coordinate is on the screen, we go to the next page. 389 * The lower y coordinate is at ul.y + Dy(im->r). 390 */ 391 case Kdown: 392 i = ul.y + Dy(im->r); 393 if(screen->r.min.y <= i && i <= screen->r.max.y){ 394 ul.y = screen->r.min.y; 395 goto Gotonext; 396 } else { 397 i = -Dy(screen->r)/2; 398 if(i < -10) 399 i += 10; 400 if(i+ul.y+Dy(im->r) <= screen->r.max.y) 401 i = screen->r.max.y - Dy(im->r) - ul.y - 1; 402 translate(Pt(0, i)); 403 } 404 break; 405 default: 406 esetcursor(&query); 407 sleep(1000); 408 esetcursor(nil); 409 break; 410 } 411 break; 412 413 case Emouse: 414 m = e.mouse; 415 switch(m.buttons){ 416 case Left: 417 oxy = m.xy; 418 xy0 = oxy; 419 do { 420 dxy = subpt(m.xy, oxy); 421 oxy = m.xy; 422 translate(dxy); 423 m = emouse(); 424 } while(m.buttons == Left); 425 if(m.buttons) { 426 dxy = subpt(xy0, oxy); 427 translate(dxy); 428 } 429 break; 430 431 case Middle: 432 do 433 m = emouse(); 434 while(m.buttons == Middle); 435 if(m.buttons) 436 break; 437 438 if(doc->npage == 0) 439 break; 440 441 if(reverse) 442 page--; 443 else 444 page++; 445 446 if((page >= doc->npage || page < 0) && !doc->fwdonly) 447 return; 448 449 showpage(page, &menu); 450 nxt = 0; 451 break; 452 453 case Right: 454 if(doc->npage == 0) 455 break; 456 457 oldpage = page; 458 n = emenuhit(RMenu, &m, &menu); 459 if(n == -1) 460 break; 461 462 if(doc->fwdonly) { 463 switch(n){ 464 case 0: /* this page */ 465 break; 466 case 1: /* next page */ 467 showpage(++page, &menu); 468 break; 469 case 2: /* exit */ 470 return; 471 } 472 break; 473 } 474 475 if(n == doc->npage) 476 return; 477 else 478 page = reverse ? doc->npage-1-n : n; 479 480 if(oldpage != page) 481 showpage(page, &menu); 482 nxt = 0; 483 break; 484 } 485 break; 486 487 case Eplumb: 488 pm = e.v; 489 if(pm->ndata <= 0){ 490 plumbfree(pm); 491 break; 492 } 493 if(showdata(pm)) { 494 s = estrdup("/tmp/pageplumbXXXXXXX"); 495 fd = opentemp(s); 496 write(fd, pm->data, pm->ndata); 497 /* lose fd reference on purpose; the file is open ORCLOSE */ 498 } else if(pm->data[0] == '/') { 499 s = estrdup(pm->data); 500 } else { 501 s = emalloc(strlen(pm->wdir)+1+pm->ndata+1); 502 sprint(s, "%s/%s", pm->wdir, pm->data); 503 cleanname(s); 504 } 505 if((i = doc->addpage(doc, s)) >= 0) { 506 page = i; 507 unhide(); 508 showpage(page, &menu); 509 } 510 free(s); 511 plumbfree(pm); 512 break; 513 } 514 } 515 } 516 517 Image *gray; 518 519 /* 520 * A draw operation that touches only the area contained in bot but not in top. 521 * mp and sp get aligned with bot.min. 522 */ 523 static void 524 gendrawdiff(Image *dst, Rectangle bot, Rectangle top, 525 Image *src, Point sp, Image *mask, Point mp) 526 { 527 Rectangle r; 528 Point origin; 529 Point delta; 530 531 if(Dx(bot)*Dy(bot) == 0) 532 return; 533 534 /* no points in bot - top */ 535 if(rectinrect(bot, top)) 536 return; 537 538 /* bot - top ≡ bot */ 539 if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){ 540 gendraw(dst, bot, src, sp, mask, mp); 541 return; 542 } 543 544 origin = bot.min; 545 /* split bot into rectangles that don't intersect top */ 546 /* left side */ 547 if(bot.min.x < top.min.x){ 548 r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y); 549 delta = subpt(r.min, origin); 550 gendraw(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta)); 551 bot.min.x = top.min.x; 552 } 553 554 /* right side */ 555 if(bot.max.x > top.max.x){ 556 r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y); 557 delta = subpt(r.min, origin); 558 gendraw(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta)); 559 bot.max.x = top.max.x; 560 } 561 562 /* top */ 563 if(bot.min.y < top.min.y){ 564 r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y); 565 delta = subpt(r.min, origin); 566 gendraw(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta)); 567 bot.min.y = top.min.y; 568 } 569 570 /* bottom */ 571 if(bot.max.y > top.max.y){ 572 r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y); 573 delta = subpt(r.min, origin); 574 gendraw(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta)); 575 bot.max.y = top.max.y; 576 } 577 } 578 579 static void 580 drawdiff(Image *dst, Rectangle bot, Rectangle top, Image *src, Image *mask, Point p) 581 { 582 gendrawdiff(dst, bot, top, src, p, mask, p); 583 } 584 585 /* 586 * Translate the image in the window by delta. 587 */ 588 static void 589 translate(Point delta) 590 { 591 Point u; 592 Rectangle r, or; 593 594 if(im == nil) 595 return; 596 597 u = pclip(addpt(ul, delta), ulrange); 598 delta = subpt(u, ul); 599 if(delta.x == 0 && delta.y == 0) 600 return; 601 602 /* 603 * The upper left corner of the image is currently at ul. 604 * We want to move it to u. 605 */ 606 or = rectaddpt(Rpt(ZP, Pt(Dx(im->r), Dy(im->r))), ul); 607 r = rectaddpt(or, delta); 608 609 draw(screen, r, screen, nil, ul); 610 ul = u; 611 612 /* fill in gray where image used to be but isn't. */ 613 drawdiff(screen, insetrect(or, -2), insetrect(r, -2), gray, nil, ZP); 614 615 /* fill in black border */ 616 drawdiff(screen, insetrect(r, -2), r, display->black, nil, ZP); 617 618 /* fill in image where it used to be off the screen. */ 619 if(rectclip(&or, screen->r)){ 620 drawdiff(screen, r, rectaddpt(or, delta), display->white, nil, im->r.min); 621 drawdiff(screen, r, rectaddpt(or, delta), im, nil, im->r.min); 622 }else{ 623 draw(screen, r, display->white, nil, im->r.min); 624 draw(screen, r, im, nil, im->r.min); 625 } 626 flushimage(display, 1); 627 } 628 629 void 630 redraw(Image *screen) 631 { 632 Rectangle r; 633 634 if(im == nil) 635 return; 636 637 ulrange.max = screen->r.max; 638 ulrange.min = subpt(screen->r.min, Pt(Dx(im->r), Dy(im->r))); 639 640 ul = pclip(ul, ulrange); 641 draw(screen, screen->r, im, nil, subpt(im->r.min, subpt(ul, screen->r.min))); 642 643 if(im->repl) 644 return; 645 646 /* fill in any outer edges */ 647 /* black border */ 648 r = rectaddpt(im->r, subpt(ul, im->r.min)); 649 border(screen, r, -2, display->black, ZP); 650 r.min = subpt(r.min, Pt(2,2)); 651 r.max = addpt(r.max, Pt(2,2)); 652 653 /* gray for the rest */ 654 if(gray == nil) { 655 gray = xallocimage(display, Rect(0,0,1,1), RGB24, 1, 0x888888FF); 656 if(gray == nil) { 657 fprint(2, "g out of memory: %r\n"); 658 wexits("mem"); 659 } 660 } 661 border(screen, r, -4000, gray, ZP); 662 // flushimage(display, 0); 663 } 664 665 void 666 eresized(int new) 667 { 668 Rectangle r; 669 r = screen->r; 670 if(new && getwindow(display, Refnone) < 0) 671 fprint(2,"can't reattach to window"); 672 ul = addpt(ul, subpt(screen->r.min, r.min)); 673 redraw(screen); 674 } 675 676 /* clip p to be in r */ 677 Point 678 pclip(Point p, Rectangle r) 679 { 680 if(p.x < r.min.x) 681 p.x = r.min.x; 682 else if(p.x >= r.max.x) 683 p.x = r.max.x-1; 684 685 if(p.y < r.min.y) 686 p.y = r.min.y; 687 else if(p.y >= r.max.y) 688 p.y = r.max.y-1; 689 690 return p; 691 } 692 693 /* 694 * resize is perhaps a misnomer. 695 * this really just grows the window to be at least dx across 696 * and dy high. if the window hits the bottom or right edge, 697 * it is backed up until it hits the top or left edge. 698 */ 699 void 700 resize(int dx, int dy) 701 { 702 static Rectangle sr; 703 Rectangle r, or; 704 705 dx += 2*Borderwidth; 706 dy += 2*Borderwidth; 707 if(wctlfd < 0){ 708 wctlfd = open("/dev/wctl", OWRITE); 709 if(wctlfd < 0) 710 return; 711 } 712 713 r = insetrect(screen->r, -Borderwidth); 714 if(Dx(r) >= dx && Dy(r) >= dy) 715 return; 716 717 if(Dx(sr)*Dy(sr) == 0) 718 sr = screenrect(); 719 720 or = r; 721 722 r.max.x = max(r.min.x+dx, r.max.x); 723 r.max.y = max(r.min.y+dy, r.max.y); 724 if(r.max.x > sr.max.x){ 725 if(Dx(r) > Dx(sr)){ 726 r.min.x = 0; 727 r.max.x = sr.max.x; 728 }else 729 r = rectaddpt(r, Pt(sr.max.x-r.max.x, 0)); 730 } 731 if(r.max.y > sr.max.y){ 732 if(Dy(r) > Dy(sr)){ 733 r.min.y = 0; 734 r.max.y = sr.max.y; 735 }else 736 r = rectaddpt(r, Pt(0, sr.max.y-r.max.y)); 737 } 738 739 /* 740 * Sometimes we can't actually grow the window big enough, 741 * and resizing it to the same shape makes it flash. 742 */ 743 if(Dx(r) == Dx(or) && Dy(r) == Dy(or)) 744 return; 745 746 fprint(wctlfd, "resize -minx %d -miny %d -maxx %d -maxy %d\n", 747 r.min.x, r.min.y, r.max.x, r.max.y); 748 } 749 750 /* 751 * If we allocimage after a resize but before flushing the draw buffer, 752 * we won't have seen the reshape event, and we won't have called 753 * getwindow, and allocimage will fail. So we flushimage before every alloc. 754 */ 755 Image* 756 xallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val) 757 { 758 flushimage(display, 0); 759 return allocimage(d, r, chan, repl, val); 760 } 761 762 /* all code below this line should be in the library, but is stolen from colors instead */ 763 static char* 764 rdenv(char *name) 765 { 766 char *v; 767 int fd, size; 768 769 fd = open(name, OREAD); 770 if(fd < 0) 771 return 0; 772 size = seek(fd, 0, 2); 773 v = malloc(size+1); 774 if(v == 0){ 775 fprint(2, "page: can't malloc: %r\n"); 776 wexits("no mem"); 777 } 778 seek(fd, 0, 0); 779 read(fd, v, size); 780 v[size] = 0; 781 close(fd); 782 return v; 783 } 784 785 void 786 newwin(void) 787 { 788 char *srv, *mntsrv; 789 char spec[100]; 790 int srvfd, cons, pid; 791 792 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){ 793 case -1: 794 fprint(2, "page: can't fork: %r\n"); 795 wexits("no fork"); 796 case 0: 797 break; 798 default: 799 wexits(0); 800 } 801 802 srv = rdenv("/env/wsys"); 803 if(srv == 0){ 804 mntsrv = rdenv("/mnt/term/env/wsys"); 805 if(mntsrv == 0){ 806 fprint(2, "page: can't find $wsys\n"); 807 wexits("srv"); 808 } 809 srv = malloc(strlen(mntsrv)+10); 810 sprint(srv, "/mnt/term%s", mntsrv); 811 free(mntsrv); 812 pid = 0; /* can't send notes to remote processes! */ 813 }else 814 pid = getpid(); 815 srvfd = open(srv, ORDWR); 816 free(srv); 817 if(srvfd == -1){ 818 fprint(2, "page: can't open %s: %r\n", srv); 819 wexits("no srv"); 820 } 821 sprint(spec, "new -pid %d", pid); 822 if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){ 823 fprint(2, "page: can't mount /mnt/wsys: %r (spec=%s)\n", spec); 824 wexits("no mount"); 825 } 826 close(srvfd); 827 unmount("/mnt/acme", "/dev"); 828 bind("/mnt/wsys", "/dev", MBEFORE); 829 cons = open("/dev/cons", OREAD); 830 if(cons==-1){ 831 NoCons: 832 fprint(2, "page: can't open /dev/cons: %r"); 833 wexits("no cons"); 834 } 835 dup(cons, 0); 836 close(cons); 837 cons = open("/dev/cons", OWRITE); 838 if(cons==-1) 839 goto NoCons; 840 dup(cons, 1); 841 dup(cons, 2); 842 close(cons); 843 // wctlfd = open("/dev/wctl", OWRITE); 844 } 845 846 Rectangle 847 screenrect(void) 848 { 849 int fd; 850 char buf[12*5]; 851 852 fd = open("/dev/screen", OREAD); 853 if(fd == -1) 854 fd=open("/mnt/term/dev/screen", OREAD); 855 if(fd == -1){ 856 fprint(2, "page: can't open /dev/screen: %r\n"); 857 wexits("window read"); 858 } 859 if(read(fd, buf, sizeof buf) != sizeof buf){ 860 fprint(2, "page: can't read /dev/screen: %r\n"); 861 wexits("screen read"); 862 } 863 close(fd); 864 return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48)); 865 } 866 867