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, int op) 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 gendrawop(dst, bot, src, sp, mask, mp, op); 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 gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); 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 gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); 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 gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); 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 gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); 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, int op) 581 { 582 gendrawdiff(dst, bot, top, src, p, mask, p, op); 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 drawop(screen, r, screen, nil, ul, S); 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, S); 614 615 /* fill in black border */ 616 drawdiff(screen, insetrect(r, -2), r, display->black, nil, ZP, S); 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), im, nil, im->r.min, S); 621 else 622 drawop(screen, r, im, nil, im->r.min, S); 623 flushimage(display, 1); 624 } 625 626 void 627 redraw(Image *screen) 628 { 629 Rectangle r; 630 631 if(im == nil) 632 return; 633 634 ulrange.max = screen->r.max; 635 ulrange.min = subpt(screen->r.min, Pt(Dx(im->r), Dy(im->r))); 636 637 ul = pclip(ul, ulrange); 638 drawop(screen, screen->r, im, nil, subpt(im->r.min, subpt(ul, screen->r.min)), S); 639 640 if(im->repl) 641 return; 642 643 /* fill in any outer edges */ 644 /* black border */ 645 r = rectaddpt(im->r, subpt(ul, im->r.min)); 646 border(screen, r, -2, display->black, ZP); 647 r.min = subpt(r.min, Pt(2,2)); 648 r.max = addpt(r.max, Pt(2,2)); 649 650 /* gray for the rest */ 651 if(gray == nil) { 652 gray = xallocimage(display, Rect(0,0,1,1), RGB24, 1, 0x888888FF); 653 if(gray == nil) { 654 fprint(2, "g out of memory: %r\n"); 655 wexits("mem"); 656 } 657 } 658 border(screen, r, -4000, gray, ZP); 659 // flushimage(display, 0); 660 } 661 662 void 663 eresized(int new) 664 { 665 Rectangle r; 666 r = screen->r; 667 if(new && getwindow(display, Refnone) < 0) 668 fprint(2,"can't reattach to window"); 669 ul = addpt(ul, subpt(screen->r.min, r.min)); 670 redraw(screen); 671 } 672 673 /* clip p to be in r */ 674 Point 675 pclip(Point p, Rectangle r) 676 { 677 if(p.x < r.min.x) 678 p.x = r.min.x; 679 else if(p.x >= r.max.x) 680 p.x = r.max.x-1; 681 682 if(p.y < r.min.y) 683 p.y = r.min.y; 684 else if(p.y >= r.max.y) 685 p.y = r.max.y-1; 686 687 return p; 688 } 689 690 /* 691 * resize is perhaps a misnomer. 692 * this really just grows the window to be at least dx across 693 * and dy high. if the window hits the bottom or right edge, 694 * it is backed up until it hits the top or left edge. 695 */ 696 void 697 resize(int dx, int dy) 698 { 699 static Rectangle sr; 700 Rectangle r, or; 701 702 dx += 2*Borderwidth; 703 dy += 2*Borderwidth; 704 if(wctlfd < 0){ 705 wctlfd = open("/dev/wctl", OWRITE); 706 if(wctlfd < 0) 707 return; 708 } 709 710 r = insetrect(screen->r, -Borderwidth); 711 if(Dx(r) >= dx && Dy(r) >= dy) 712 return; 713 714 if(Dx(sr)*Dy(sr) == 0) 715 sr = screenrect(); 716 717 or = r; 718 719 r.max.x = max(r.min.x+dx, r.max.x); 720 r.max.y = max(r.min.y+dy, r.max.y); 721 if(r.max.x > sr.max.x){ 722 if(Dx(r) > Dx(sr)){ 723 r.min.x = 0; 724 r.max.x = sr.max.x; 725 }else 726 r = rectaddpt(r, Pt(sr.max.x-r.max.x, 0)); 727 } 728 if(r.max.y > sr.max.y){ 729 if(Dy(r) > Dy(sr)){ 730 r.min.y = 0; 731 r.max.y = sr.max.y; 732 }else 733 r = rectaddpt(r, Pt(0, sr.max.y-r.max.y)); 734 } 735 736 /* 737 * Sometimes we can't actually grow the window big enough, 738 * and resizing it to the same shape makes it flash. 739 */ 740 if(Dx(r) == Dx(or) && Dy(r) == Dy(or)) 741 return; 742 743 fprint(wctlfd, "resize -minx %d -miny %d -maxx %d -maxy %d\n", 744 r.min.x, r.min.y, r.max.x, r.max.y); 745 } 746 747 /* 748 * If we allocimage after a resize but before flushing the draw buffer, 749 * we won't have seen the reshape event, and we won't have called 750 * getwindow, and allocimage will fail. So we flushimage before every alloc. 751 */ 752 Image* 753 xallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val) 754 { 755 flushimage(display, 0); 756 return allocimage(d, r, chan, repl, val); 757 } 758 759 /* all code below this line should be in the library, but is stolen from colors instead */ 760 static char* 761 rdenv(char *name) 762 { 763 char *v; 764 int fd, size; 765 766 fd = open(name, OREAD); 767 if(fd < 0) 768 return 0; 769 size = seek(fd, 0, 2); 770 v = malloc(size+1); 771 if(v == 0){ 772 fprint(2, "page: can't malloc: %r\n"); 773 wexits("no mem"); 774 } 775 seek(fd, 0, 0); 776 read(fd, v, size); 777 v[size] = 0; 778 close(fd); 779 return v; 780 } 781 782 void 783 newwin(void) 784 { 785 char *srv, *mntsrv; 786 char spec[100]; 787 int srvfd, cons, pid; 788 789 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){ 790 case -1: 791 fprint(2, "page: can't fork: %r\n"); 792 wexits("no fork"); 793 case 0: 794 break; 795 default: 796 wexits(0); 797 } 798 799 srv = rdenv("/env/wsys"); 800 if(srv == 0){ 801 mntsrv = rdenv("/mnt/term/env/wsys"); 802 if(mntsrv == 0){ 803 fprint(2, "page: can't find $wsys\n"); 804 wexits("srv"); 805 } 806 srv = malloc(strlen(mntsrv)+10); 807 sprint(srv, "/mnt/term%s", mntsrv); 808 free(mntsrv); 809 pid = 0; /* can't send notes to remote processes! */ 810 }else 811 pid = getpid(); 812 srvfd = open(srv, ORDWR); 813 free(srv); 814 if(srvfd == -1){ 815 fprint(2, "page: can't open %s: %r\n", srv); 816 wexits("no srv"); 817 } 818 sprint(spec, "new -pid %d", pid); 819 if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){ 820 fprint(2, "page: can't mount /mnt/wsys: %r (spec=%s)\n", spec); 821 wexits("no mount"); 822 } 823 close(srvfd); 824 unmount("/mnt/acme", "/dev"); 825 bind("/mnt/wsys", "/dev", MBEFORE); 826 cons = open("/dev/cons", OREAD); 827 if(cons==-1){ 828 NoCons: 829 fprint(2, "page: can't open /dev/cons: %r"); 830 wexits("no cons"); 831 } 832 dup(cons, 0); 833 close(cons); 834 cons = open("/dev/cons", OWRITE); 835 if(cons==-1) 836 goto NoCons; 837 dup(cons, 1); 838 dup(cons, 2); 839 close(cons); 840 // wctlfd = open("/dev/wctl", OWRITE); 841 } 842 843 Rectangle 844 screenrect(void) 845 { 846 int fd; 847 char buf[12*5]; 848 849 fd = open("/dev/screen", OREAD); 850 if(fd == -1) 851 fd=open("/mnt/term/dev/screen", OREAD); 852 if(fd == -1){ 853 fprint(2, "page: can't open /dev/screen: %r\n"); 854 wexits("window read"); 855 } 856 if(read(fd, buf, sizeof buf) != sizeof buf){ 857 fprint(2, "page: can't read /dev/screen: %r\n"); 858 wexits("screen read"); 859 } 860 close(fd); 861 return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48)); 862 } 863 864