1 #include "dat.h" 2 #include "fns.h" 3 #include "kernel.h" 4 #include "error.h" 5 6 #include <draw.h> 7 #include <memdraw.h> 8 #include <cursor.h> 9 #include "keyboard.h" 10 11 enum 12 { 13 Margin = 4, 14 Lsize = 100, 15 }; 16 17 extern Memimage *screenimage; 18 19 extern int kproc1(char*, void (*)(void*), void*, int); 20 21 static ulong* attachwindow(Rectangle*, ulong*, int*, int*); 22 23 static void plan9readmouse(void*); 24 static void plan9readkeybd(void*); 25 static int mapspecials(char *s1, char *s2, int *n); 26 27 int usenewwin = 1; 28 int kbdiscons; 29 static int truedepth; 30 31 static int datafd; 32 static int ctlfd; 33 static int mousefd = -1; 34 static int keybdfd; 35 static int mousepid = -1; 36 static int keybdpid = -1; 37 static int cursfd; 38 static char winname[64]; 39 40 /* Following updated by attachwindow() asynchronously */ 41 static QLock ql; 42 static Rectangle tiler; 43 static ulong* data; 44 static uchar* loadbuf; 45 static int cursfd; 46 static int imageid; 47 static Rectangle imager; 48 static uchar *chunk; 49 static int chunksize; 50 static int dispbufsize; 51 52 #define NINFO 12*12 53 #define HDR 21 54 55 56 void 57 killrefresh(void) 58 { 59 if(mousepid < 0) 60 return; 61 close(mousefd); 62 close(ctlfd); 63 close(datafd); 64 postnote(PNPROC, mousepid, Eintr); 65 postnote(PNPROC, keybdpid, Eintr); 66 } 67 68 uchar* 69 attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen) 70 { 71 int fd; 72 char *p, buf[128], info[NINFO+1]; 73 74 if(usenewwin){ 75 p = getenv("wsys"); 76 if(p == nil) 77 return nil; 78 79 fd = open(p, ORDWR); 80 if(fd < 0) { 81 fprint(2, "attachscreen: can't open window manager: %r\n"); 82 return nil; 83 } 84 sprint(buf, "new -dx %d -dy %d", Xsize+2*Margin, Ysize+2*Margin); 85 if(mount(fd, -1, "/mnt/wsys", MREPL, buf) < 0) { 86 fprint(2, "attachscreen: can't mount window manager: %r\n"); 87 return nil; 88 } 89 if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){ 90 fprint(2, "attachscreen: can't bind /mnt/wsys before /dev: %r\n"); 91 return nil; 92 } 93 } 94 95 cursfd = open("/dev/cursor", OWRITE); 96 if(cursfd < 0) { 97 fprint(2, "attachscreen: open cursor: %r\n"); 98 return nil; 99 } 100 101 /* Set up graphics window console (chars->gkbdq) */ 102 keybdfd = open("/dev/cons", OREAD); 103 if(keybdfd < 0) { 104 fprint(2, "attachscreen: open keyboard: %r\n"); 105 return nil; 106 } 107 mousefd = open("/dev/mouse", ORDWR); 108 if(mousefd < 0){ 109 fprint(2, "attachscreen: can't open mouse: %r\n"); 110 return nil; 111 } 112 if(usenewwin || 1){ 113 fd = open("/dev/consctl", OWRITE); 114 if(fd < 0) 115 fprint(2, "attachscreen: open /dev/consctl: %r\n"); 116 if(write(fd, "rawon", 5) != 5) 117 fprint(2, "attachscreen: write /dev/consctl: %r\n"); 118 } 119 120 /* Set up graphics files */ 121 ctlfd = open("/dev/draw/new", ORDWR); 122 if(ctlfd < 0){ 123 fprint(2, "attachscreen: can't open graphics control file: %r\n"); 124 return nil; 125 } 126 if(read(ctlfd, info, sizeof info) < NINFO){ 127 close(ctlfd); 128 fprint(2, "attachscreen: can't read graphics control file: %r\n"); 129 return nil; 130 } 131 sprint(buf, "/dev/draw/%d/data", atoi(info+0*12)); 132 datafd = open(buf, ORDWR|OCEXEC); 133 if(datafd < 0){ 134 close(ctlfd); 135 fprint(2, "attachscreen: can't read graphics data file: %r\n"); 136 return nil; 137 } 138 dispbufsize = iounit(datafd); 139 if(dispbufsize <= 0) 140 dispbufsize = 8000; 141 if(dispbufsize < 512){ 142 close(ctlfd); 143 close(datafd); 144 fprint(2, "attachscreen: iounit %d too small\n", dispbufsize); 145 return nil; 146 } 147 chunksize = dispbufsize - 64; 148 149 if(attachwindow(r, chan, d, width) == nil){ 150 close(ctlfd); 151 close(datafd); 152 return nil; 153 } 154 155 mousepid = kproc1("readmouse", plan9readmouse, nil, 0); 156 keybdpid = kproc1("readkbd", plan9readkeybd, nil, 0); 157 158 fd = open("/dev/label", OWRITE); 159 if(fd >= 0){ 160 snprint(buf, sizeof(buf), "inferno %d", getpid()); 161 write(fd, buf, strlen(buf)); 162 close(fd); 163 } 164 165 *softscreen = 1; 166 return (uchar*)data; 167 } 168 169 static ulong* 170 attachwindow(Rectangle *r, ulong *chan, int *d, int *width) 171 { 172 int n, fd, nb; 173 char buf[256]; 174 uchar ubuf[128]; 175 ulong imagechan; 176 177 /* 178 * Discover name of window 179 */ 180 fd = open("/mnt/wsys/winname", OREAD); 181 if(fd<0 || (n=read(fd, winname, sizeof winname))<=0){ 182 fprint(2, "attachwindow: can only run inferno under rio, not stand-alone\n"); 183 return nil; 184 } 185 close(fd); 186 /* 187 * If had previous window, release it 188 */ 189 if(imageid > 0){ 190 ubuf[0] = 'f'; 191 BPLONG(ubuf+1, imageid); 192 if(write(datafd, ubuf, 1+4) != 1+4) 193 fprint(2, "attachwindow: cannot free old window: %r\n"); 194 } 195 /* 196 * Allocate image pointing to window, and discover its ID 197 */ 198 ubuf[0] = 'n'; 199 ++imageid; 200 BPLONG(ubuf+1, imageid); 201 ubuf[5] = n; 202 memmove(ubuf+6, winname, n); 203 if(write(datafd, ubuf, 6+n) != 6+n){ 204 fprint(2, "attachwindow: cannot bind %d to window id '%s': %r\n", imageid, winname); 205 return nil; 206 } 207 if(read(ctlfd, buf, sizeof buf) < 12*12){ 208 fprint(2, "attachwindow: cannot read window id: %r\n"); 209 return nil; 210 } 211 imagechan = strtochan(buf+2*12); 212 truedepth = chantodepth(imagechan); 213 if(truedepth == 0){ 214 fprint(2, "attachwindow: cannot handle window depth specifier %.12s\n", buf+2*12); 215 return nil; 216 } 217 218 /* 219 * Report back 220 */ 221 if(chan != nil) 222 *chan = imagechan; 223 if(d != nil) 224 *d = chantodepth(imagechan); 225 nb = 0; 226 if(r != nil){ 227 Xsize = atoi(buf+6*12)-atoi(buf+4*12)-2*Margin; 228 Ysize = atoi(buf+7*12)-atoi(buf+5*12)-2*Margin; 229 r->min.x = 0; 230 r->min.y = 0; 231 r->max.x = Xsize; 232 r->max.y = Ysize; 233 nb = bytesperline(*r, truedepth); 234 data = malloc(nb*Ysize); 235 loadbuf = malloc(nb*Lsize+1); 236 chunk = malloc(HDR+chunksize+5); /* +5 for flush (1 old, 5 new) */ 237 } 238 imager.min.x = atoi(buf+4*12); 239 imager.min.y = atoi(buf+5*12); 240 imager.max.x = atoi(buf+6*12); 241 imager.max.y = atoi(buf+7*12); 242 243 if(width != nil) 244 *width = nb/4; 245 246 tiler.min.x = atoi(buf+4*12)+Margin; 247 tiler.min.y = atoi(buf+5*12)+Margin; 248 tiler.max.x = atoi(buf+6*12)-Margin; 249 tiler.max.y = atoi(buf+7*12)-Margin; 250 251 return data; 252 } 253 254 static int 255 plan9loadimage(Rectangle r, uchar *data, int ndata) 256 { 257 long dy; 258 int n, bpl; 259 260 if(!rectinrect(r, imager)){ 261 werrstr("loadimage: bad rectangle"); 262 return -1; 263 } 264 bpl = bytesperline(r, truedepth); 265 n = bpl*Dy(r); 266 if(n > ndata){ 267 werrstr("loadimage: insufficient data"); 268 return -1; 269 } 270 ndata = 0; 271 while(r.max.y > r.min.y){ 272 dy = r.max.y - r.min.y; 273 if(dy*bpl> chunksize) 274 dy = chunksize/bpl; 275 n = dy*bpl; 276 chunk[0] = 'y'; 277 BPLONG(chunk+1, imageid); 278 BPLONG(chunk+5, r.min.x); 279 BPLONG(chunk+9, r.min.y); 280 BPLONG(chunk+13, r.max.x); 281 BPLONG(chunk+17, r.min.y+dy); 282 memmove(chunk+21, data, n); 283 ndata += n; 284 data += n; 285 r.min.y += dy; 286 n += 21; 287 if(r.min.y >= r.max.y) /* flush to screen */ 288 chunk[n++] = 'v'; 289 if(write(datafd, chunk, n) != n) 290 return -1; 291 } 292 return ndata; 293 } 294 295 static void 296 _flushmemscreen(Rectangle r) 297 { 298 int n, dy, l; 299 Rectangle rr; 300 301 if(data == nil || loadbuf == nil || chunk==nil) 302 return; 303 if(!rectclip(&r, Rect(0, 0, Xsize, Ysize))) 304 return; 305 if(!rectclip(&r, Rect(0, 0, Dx(tiler), Dy(tiler)))) 306 return; 307 if(Dx(r)<=0 || Dy(r)<=0) 308 return; 309 l = bytesperline(r, truedepth); 310 while(r.min.y < r.max.y){ 311 dy = Dy(r); 312 if(dy > Lsize) 313 dy = Lsize; 314 rr = r; 315 rr.max.y = rr.min.y+dy; 316 n = unloadmemimage(screenimage, rr, loadbuf, l*dy); 317 /* offset from (0,0) to window */ 318 rr.min.x += tiler.min.x; 319 rr.min.y += tiler.min.y; 320 rr.max.x += tiler.min.x; 321 rr.max.y += tiler.min.y; 322 if(plan9loadimage(rr, loadbuf, n) != n) 323 fprint(2, "flushmemscreen: %d bytes: %r\n", n); 324 r.min.y += dy; 325 } 326 } 327 328 void 329 flushmemscreen(Rectangle r) 330 { 331 qlock(&ql); 332 _flushmemscreen(r); 333 qunlock(&ql); 334 } 335 336 void 337 drawcursor(Drawcursor *c) 338 { 339 int j, i, h, w, bpl; 340 uchar *bc, *bs, *cclr, *cset, curs[2*4+2*2*16]; 341 342 /* Set the default system cursor */ 343 if(c->data == nil) { 344 write(cursfd, curs, 0); 345 return; 346 } 347 348 BPLONG(curs+0*4, c->hotx); 349 BPLONG(curs+1*4, c->hoty); 350 351 w = (c->maxx-c->minx); 352 h = (c->maxy-c->miny)/2; 353 354 cclr = curs+2*4; 355 cset = curs+2*4+2*16; 356 bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 1); 357 bc = c->data; 358 bs = c->data + h*bpl; 359 360 if(h > 16) 361 h = 16; 362 if(w > 16) 363 w = 16; 364 w /= 8; 365 for(i = 0; i < h; i++) { 366 for(j = 0; j < w; j++) { 367 cclr[j] = bc[j]; 368 cset[j] = bs[j]; 369 } 370 bc += bpl; 371 bs += bpl; 372 cclr += 2; 373 cset += 2; 374 } 375 write(cursfd, curs, sizeof curs); 376 } 377 378 static int 379 checkmouse(char *buf, int n) 380 { 381 int x, y, tick, b; 382 static int lastb, lastt, lastx, lasty, lastclick; 383 384 switch(n){ 385 default: 386 kwerrstr("atomouse: bad count"); 387 return -1; 388 389 case 1+4*12: 390 if(buf[0] == 'r'){ 391 qlock(&ql); 392 if(attachwindow(nil, nil, nil, nil) == nil) { 393 qunlock(&ql); 394 return -1; 395 } 396 _flushmemscreen(Rect(0, 0, Xsize, Ysize)); 397 qunlock(&ql); 398 } 399 x = atoi(buf+1+0*12) - tiler.min.x; 400 y = atoi(buf+1+1*12) - tiler.min.y; 401 b = atoi(buf+1+2*12); 402 tick = atoi(buf+1+3*12); 403 if(b && lastb == 0){ /* button newly pressed */ 404 if(b==lastclick && tick-lastt<400 405 && abs(x-lastx)<10 && abs(y-lasty)<10) 406 b |= (1<<8); 407 lastt = tick; 408 lastclick = b&0xff; 409 lastx = x; 410 lasty = y; 411 } 412 lastb = b&0xff; 413 //mouse.msec = tick; 414 mousetrack(b, x, y, 0); 415 return n; 416 } 417 } 418 419 static void 420 plan9readmouse(void *v) 421 { 422 int n; 423 char buf[128]; 424 425 USED(v); 426 for(;;){ 427 n = read(mousefd, buf, sizeof(buf)); 428 if(n < 0) /* probably interrupted */ 429 _exits(0); 430 checkmouse(buf, n); 431 } 432 } 433 434 static void 435 plan9readkeybd(void*) 436 { 437 int n, partial; 438 char buf[32]; 439 char dbuf[32 * 3]; /* overestimate but safe */ 440 441 partial = 0; 442 for(;;){ 443 n = read(keybdfd, buf + partial, sizeof(buf) - partial); 444 if(n < 0) /* probably interrupted */ 445 _exits(0); 446 partial += n; 447 n = mapspecials(dbuf, buf, &partial); 448 qproduce(gkbdq, dbuf, n); 449 } 450 } 451 452 void 453 setpointer(int x, int y) 454 { 455 char buf[50]; 456 int n; 457 458 if(mousefd < 0) 459 return; 460 x += tiler.min.x; 461 y += tiler.min.y; 462 n = snprint(buf, sizeof buf, "m%11d %11d ", x, y); 463 write(mousefd, buf, n); 464 } 465 466 /* 467 * plan9 keyboard codes; from /sys/include/keyboard.h; can't include directly 468 * because constant names clash. 469 */ 470 enum { 471 P9KF= 0xF000, /* Rune: beginning of private Unicode space */ 472 P9Spec= 0xF800, 473 /* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */ 474 Khome= P9KF|0x0D, 475 Kup= P9KF|0x0E, 476 Kpgup= P9KF|0x0F, 477 Kprint= P9KF|0x10, 478 Kleft= P9KF|0x11, 479 Kright= P9KF|0x12, 480 Kdown= P9Spec|0x00, 481 Kview= P9Spec|0x00, 482 Kpgdown= P9KF|0x13, 483 Kins= P9KF|0x14, 484 Kend= KF|0x18, 485 486 Kalt= P9KF|0x15, 487 Kshift= P9KF|0x16, 488 Kctl= P9KF|0x17, 489 }; 490 491 /* 492 * translate plan 9 special characters from s2 (of length *n) into s1; 493 * return number of chars placed into s1. 494 * any trailing incomplete chars are moved to the beginning of s2, 495 * and *n set to the number moved there. 496 */ 497 static int 498 mapspecials(char *s1, char *s2, int *n) 499 { 500 char *s, *d, *es2; 501 Rune r; 502 d = s1; 503 s = s2; 504 es2 = s2 + *n; 505 while (fullrune(s, es2 - s)) { 506 s += chartorune(&r, s); 507 switch (r) { 508 case Kshift: 509 r = LShift; 510 break; 511 case Kctl: 512 r = LCtrl; 513 break; 514 case Kalt: 515 r = LAlt; 516 break; 517 case Khome: 518 r = Home; 519 break; 520 case Kend: 521 r = End; 522 break; 523 case Kup: 524 r = Up; 525 break; 526 case Kdown: 527 r = Down; 528 break; 529 case Kleft: 530 r = Left; 531 break; 532 case Kright: 533 r = Right; 534 break; 535 case Kpgup: 536 r = Pgup; 537 break; 538 case Kpgdown: 539 r = Pgdown; 540 break; 541 case Kins: 542 r = Ins; 543 break; 544 /* 545 * function keys 546 */ 547 case P9KF|1: 548 case P9KF|2: 549 case P9KF|3: 550 case P9KF|4: 551 case P9KF|5: 552 case P9KF|6: 553 case P9KF|7: 554 case P9KF|8: 555 case P9KF|9: 556 case P9KF|10: 557 case P9KF|11: 558 case P9KF|12: 559 r = (r - P9KF) + KF; 560 } 561 d += runetochar(d, &r); 562 } 563 *n = es2 - s; 564 memmove(s2, s, *n); 565 return d - s1; 566 } 567