srv.c (10538B)
1 /* 2 * Window system protocol server. 3 */ 4 5 #include <u.h> 6 #include <libc.h> 7 #include <thread.h> 8 #include <draw.h> 9 #include <memdraw.h> 10 #include <memlayer.h> 11 #include <keyboard.h> 12 #include <mouse.h> 13 #include <cursor.h> 14 #include <drawfcall.h> 15 #include "devdraw.h" 16 17 static void runmsg(Client*, Wsysmsg*); 18 static void replymsg(Client*, Wsysmsg*); 19 static void matchkbd(Client*); 20 static void matchmouse(Client*); 21 static void serveproc(void*); 22 static void listenproc(void*); 23 Client *client0; 24 25 int trace = 0; 26 static char *srvname; 27 static int afd; 28 static char adir[40]; 29 30 static void 31 usage(void) 32 { 33 fprint(2, "usage: devdraw (don't run directly)\n"); 34 threadexitsall("usage"); 35 } 36 37 void 38 threadmain(int argc, char **argv) 39 { 40 char *p; 41 42 ARGBEGIN{ 43 case 'D': /* for good ps -a listings */ 44 break; 45 case 'f': /* fall through for backward compatibility */ 46 case 'g': 47 case 'b': 48 break; 49 case 's': 50 // TODO: Update usage, man page. 51 srvname = EARGF(usage()); 52 break; 53 default: 54 usage(); 55 }ARGEND 56 57 memimageinit(); 58 fmtinstall('H', encodefmt); 59 if((p = getenv("DEVDRAWTRACE")) != nil) 60 trace = atoi(p); 61 62 if(srvname == nil) { 63 client0 = mallocz(sizeof(Client), 1); 64 if(client0 == nil){ 65 fprint(2, "initdraw: allocating client0: out of memory"); 66 abort(); 67 } 68 client0->displaydpi = 100; 69 client0->rfd = 3; 70 client0->wfd = 4; 71 72 /* 73 * Move the protocol off stdin/stdout so that 74 * any inadvertent prints don't screw things up. 75 */ 76 dup(0,3); 77 dup(1,4); 78 close(0); 79 close(1); 80 open("/dev/null", OREAD); 81 open("/dev/null", OWRITE); 82 } 83 84 fmtinstall('W', drawfcallfmt); 85 gfx_main(); 86 } 87 88 void 89 gfx_started(void) 90 { 91 char *ns, *addr; 92 93 if(srvname == nil) { 94 // Legacy mode: serving single client on pipes. 95 proccreate(serveproc, client0, 0); 96 return; 97 } 98 99 // Server mode. 100 if((ns = getns()) == nil) 101 sysfatal("out of memory"); 102 103 addr = smprint("unix!%s/%s", ns, srvname); 104 free(ns); 105 if(addr == nil) 106 sysfatal("out of memory"); 107 108 if((afd = announce(addr, adir)) < 0) 109 sysfatal("announce %s: %r", addr); 110 111 proccreate(listenproc, nil, 0); 112 } 113 114 static void 115 listenproc(void *v) 116 { 117 Client *c; 118 int fd; 119 char dir[40]; 120 121 USED(v); 122 123 for(;;) { 124 fd = listen(adir, dir); 125 if(fd < 0) 126 sysfatal("listen: %r"); 127 c = mallocz(sizeof(Client), 1); 128 if(c == nil){ 129 fprint(2, "initdraw: allocating client0: out of memory"); 130 abort(); 131 } 132 c->displaydpi = 100; 133 c->rfd = fd; 134 c->wfd = fd; 135 proccreate(serveproc, c, 0); 136 } 137 } 138 139 static void 140 serveproc(void *v) 141 { 142 Client *c; 143 uchar buf[4], *mbuf; 144 int nmbuf, n, nn; 145 Wsysmsg m; 146 147 c = v; 148 mbuf = nil; 149 nmbuf = 0; 150 while((n = read(c->rfd, buf, 4)) == 4){ 151 GET(buf, n); 152 if(n > nmbuf){ 153 free(mbuf); 154 mbuf = malloc(4+n); 155 if(mbuf == nil) 156 sysfatal("out of memory"); 157 nmbuf = n; 158 } 159 memmove(mbuf, buf, 4); 160 nn = readn(c->rfd, mbuf+4, n-4); 161 if(nn != n-4) { 162 fprint(2, "serveproc: eof during message\n"); 163 break; 164 } 165 166 /* pick off messages one by one */ 167 if(convM2W(mbuf, nn+4, &m) <= 0) { 168 fprint(2, "serveproc: cannot convert message\n"); 169 break; 170 } 171 if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m); 172 runmsg(c, &m); 173 } 174 175 if(c == client0) { 176 rpc_shutdown(); 177 threadexitsall(nil); 178 } 179 } 180 181 static void 182 replyerror(Client *c, Wsysmsg *m) 183 { 184 char err[256]; 185 186 rerrstr(err, sizeof err); 187 m->type = Rerror; 188 m->error = err; 189 replymsg(c, m); 190 } 191 192 /* 193 * Handle a single wsysmsg. 194 * Might queue for later (kbd, mouse read) 195 */ 196 static void 197 runmsg(Client *c, Wsysmsg *m) 198 { 199 static uchar buf[65536]; 200 int n; 201 Memimage *i; 202 203 switch(m->type){ 204 case Tctxt: 205 c->wsysid = strdup(m->id); 206 replymsg(c, m); 207 break; 208 209 case Tinit: 210 i = rpc_attach(c, m->label, m->winsize); 211 if(i == nil) { 212 replyerror(c, m); 213 break; 214 } 215 draw_initdisplaymemimage(c, i); 216 replymsg(c, m); 217 break; 218 219 case Trdmouse: 220 qlock(&c->eventlk); 221 if((c->mousetags.wi+1)%nelem(c->mousetags.t) == c->mousetags.ri) { 222 qunlock(&c->eventlk); 223 werrstr("too many queued mouse reads"); 224 replyerror(c, m); 225 break; 226 } 227 c->mousetags.t[c->mousetags.wi++] = m->tag; 228 if(c->mousetags.wi == nelem(c->mousetags.t)) 229 c->mousetags.wi = 0; 230 c->mouse.stall = 0; 231 matchmouse(c); 232 qunlock(&c->eventlk); 233 break; 234 235 case Trdkbd: 236 case Trdkbd4: 237 qlock(&c->eventlk); 238 if((c->kbdtags.wi+1)%nelem(c->kbdtags.t) == c->kbdtags.ri) { 239 qunlock(&c->eventlk); 240 werrstr("too many queued keyboard reads"); 241 replyerror(c, m); 242 break; 243 } 244 c->kbdtags.t[c->kbdtags.wi++] = (m->tag<<1) | (m->type==Trdkbd4); 245 if(c->kbdtags.wi == nelem(c->kbdtags.t)) 246 c->kbdtags.wi = 0; 247 c->kbd.stall = 0; 248 matchkbd(c); 249 qunlock(&c->eventlk); 250 break; 251 252 case Tmoveto: 253 c->impl->rpc_setmouse(c, m->mouse.xy); 254 replymsg(c, m); 255 break; 256 257 case Tcursor: 258 if(m->arrowcursor) 259 c->impl->rpc_setcursor(c, nil, nil); 260 else { 261 scalecursor(&m->cursor2, &m->cursor); 262 c->impl->rpc_setcursor(c, &m->cursor, &m->cursor2); 263 } 264 replymsg(c, m); 265 break; 266 267 case Tcursor2: 268 if(m->arrowcursor) 269 c->impl->rpc_setcursor(c, nil, nil); 270 else 271 c->impl->rpc_setcursor(c, &m->cursor, &m->cursor2); 272 replymsg(c, m); 273 break; 274 275 case Tbouncemouse: 276 c->impl->rpc_bouncemouse(c, m->mouse); 277 replymsg(c, m); 278 break; 279 280 case Tlabel: 281 c->impl->rpc_setlabel(c, m->label); 282 replymsg(c, m); 283 break; 284 285 case Trdsnarf: 286 m->snarf = rpc_getsnarf(); 287 replymsg(c, m); 288 free(m->snarf); 289 break; 290 291 case Twrsnarf: 292 rpc_putsnarf(m->snarf); 293 replymsg(c, m); 294 break; 295 296 case Trddraw: 297 n = m->count; 298 if(n > sizeof buf) 299 n = sizeof buf; 300 n = draw_dataread(c, buf, n); 301 if(n < 0) 302 replyerror(c, m); 303 else{ 304 m->count = n; 305 m->data = buf; 306 replymsg(c, m); 307 } 308 break; 309 310 case Twrdraw: 311 if(draw_datawrite(c, m->data, m->count) < 0) 312 replyerror(c, m); 313 else 314 replymsg(c, m); 315 break; 316 317 case Ttop: 318 c->impl->rpc_topwin(c); 319 replymsg(c, m); 320 break; 321 322 case Tresize: 323 c->impl->rpc_resizewindow(c, m->rect); 324 replymsg(c, m); 325 break; 326 } 327 } 328 329 /* 330 * Reply to m. 331 */ 332 static void 333 replymsg(Client *c, Wsysmsg *m) 334 { 335 int n; 336 337 /* T -> R msg */ 338 if(m->type%2 == 0) 339 m->type++; 340 341 if(trace) fprint(2, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), m); 342 /* copy to output buffer */ 343 n = sizeW2M(m); 344 345 qlock(&c->wfdlk); 346 if(n > c->nmbuf){ 347 free(c->mbuf); 348 c->mbuf = malloc(n); 349 if(c->mbuf == nil) 350 sysfatal("out of memory"); 351 c->nmbuf = n; 352 } 353 convW2M(m, c->mbuf, n); 354 if(write(c->wfd, c->mbuf, n) != n) 355 fprint(2, "client write: %r\n"); 356 qunlock(&c->wfdlk); 357 } 358 359 /* 360 * Match queued kbd reads with queued kbd characters. 361 */ 362 static void 363 matchkbd(Client *c) 364 { 365 int tag; 366 Wsysmsg m; 367 368 if(c->kbd.stall) 369 return; 370 while(c->kbd.ri != c->kbd.wi && c->kbdtags.ri != c->kbdtags.wi){ 371 tag = c->kbdtags.t[c->kbdtags.ri++]; 372 m.type = Rrdkbd; 373 if(tag&1) 374 m.type = Rrdkbd4; 375 m.tag = tag>>1; 376 if(c->kbdtags.ri == nelem(c->kbdtags.t)) 377 c->kbdtags.ri = 0; 378 m.rune = c->kbd.r[c->kbd.ri++]; 379 if(c->kbd.ri == nelem(c->kbd.r)) 380 c->kbd.ri = 0; 381 replymsg(c, &m); 382 } 383 } 384 385 // matchmouse matches queued mouse reads with queued mouse events. 386 // It must be called with c->eventlk held. 387 static void 388 matchmouse(Client *c) 389 { 390 Wsysmsg m; 391 392 if(canqlock(&c->eventlk)) { 393 fprint(2, "misuse of matchmouse\n"); 394 abort(); 395 } 396 397 while(c->mouse.ri != c->mouse.wi && c->mousetags.ri != c->mousetags.wi){ 398 m.type = Rrdmouse; 399 m.tag = c->mousetags.t[c->mousetags.ri++]; 400 if(c->mousetags.ri == nelem(c->mousetags.t)) 401 c->mousetags.ri = 0; 402 m.mouse = c->mouse.m[c->mouse.ri]; 403 m.resized = c->mouse.resized; 404 c->mouse.resized = 0; 405 /* 406 if(m.resized) 407 fprint(2, "sending resize\n"); 408 */ 409 c->mouse.ri++; 410 if(c->mouse.ri == nelem(c->mouse.m)) 411 c->mouse.ri = 0; 412 replymsg(c, &m); 413 } 414 } 415 416 void 417 gfx_mouseresized(Client *c) 418 { 419 gfx_mousetrack(c, -1, -1, -1, -1); 420 } 421 422 void 423 gfx_mousetrack(Client *c, int x, int y, int b, uint ms) 424 { 425 Mouse *m; 426 427 qlock(&c->eventlk); 428 if(x == -1 && y == -1 && b == -1 && ms == -1) { 429 Mouse *copy; 430 // repeat last mouse event for resize 431 if(c->mouse.ri == 0) 432 copy = &c->mouse.m[nelem(c->mouse.m)-1]; 433 else 434 copy = &c->mouse.m[c->mouse.ri-1]; 435 x = copy->xy.x; 436 y = copy->xy.y; 437 b = copy->buttons; 438 ms = copy->msec; 439 c->mouse.resized = 1; 440 } 441 if(x < c->mouserect.min.x) 442 x = c->mouserect.min.x; 443 if(x > c->mouserect.max.x) 444 x = c->mouserect.max.x; 445 if(y < c->mouserect.min.y) 446 y = c->mouserect.min.y; 447 if(y > c->mouserect.max.y) 448 y = c->mouserect.max.y; 449 450 // If reader has stopped reading, don't bother. 451 // If reader is completely caught up, definitely queue. 452 // Otherwise, queue only button change events. 453 if(!c->mouse.stall) 454 if(c->mouse.wi == c->mouse.ri || c->mouse.last.buttons != b){ 455 m = &c->mouse.last; 456 m->xy.x = x; 457 m->xy.y = y; 458 m->buttons = b; 459 m->msec = ms; 460 461 c->mouse.m[c->mouse.wi] = *m; 462 if(++c->mouse.wi == nelem(c->mouse.m)) 463 c->mouse.wi = 0; 464 if(c->mouse.wi == c->mouse.ri){ 465 c->mouse.stall = 1; 466 c->mouse.ri = 0; 467 c->mouse.wi = 1; 468 c->mouse.m[0] = *m; 469 } 470 matchmouse(c); 471 } 472 qunlock(&c->eventlk); 473 } 474 475 // kputc adds ch to the keyboard buffer. 476 // It must be called with c->eventlk held. 477 static void 478 kputc(Client *c, int ch) 479 { 480 if(canqlock(&c->eventlk)) { 481 fprint(2, "misuse of kputc\n"); 482 abort(); 483 } 484 485 c->kbd.r[c->kbd.wi++] = ch; 486 if(c->kbd.wi == nelem(c->kbd.r)) 487 c->kbd.wi = 0; 488 if(c->kbd.ri == c->kbd.wi) 489 c->kbd.stall = 1; 490 matchkbd(c); 491 } 492 493 // gfx_abortcompose stops any pending compose sequence, 494 // because a mouse button has been clicked. 495 // It is called from the graphics thread with no locks held. 496 void 497 gfx_abortcompose(Client *c) 498 { 499 qlock(&c->eventlk); 500 if(c->kbd.alting) { 501 c->kbd.alting = 0; 502 c->kbd.nk = 0; 503 } 504 qunlock(&c->eventlk); 505 } 506 507 // gfx_keystroke records a single-rune keystroke. 508 // It is called from the graphics thread with no locks held. 509 void 510 gfx_keystroke(Client *c, int ch) 511 { 512 int i; 513 514 qlock(&c->eventlk); 515 if(ch == Kalt){ 516 c->kbd.alting = !c->kbd.alting; 517 c->kbd.nk = 0; 518 qunlock(&c->eventlk); 519 return; 520 } 521 if(ch == Kcmd+'r') { 522 if(c->forcedpi) 523 c->forcedpi = 0; 524 else if(c->displaydpi >= 200) 525 c->forcedpi = 100; 526 else 527 c->forcedpi = 225; 528 qunlock(&c->eventlk); 529 c->impl->rpc_resizeimg(c); 530 return; 531 } 532 if(!c->kbd.alting){ 533 kputc(c, ch); 534 qunlock(&c->eventlk); 535 return; 536 } 537 if(c->kbd.nk >= nelem(c->kbd.k)) // should not happen 538 c->kbd.nk = 0; 539 c->kbd.k[c->kbd.nk++] = ch; 540 ch = latin1(c->kbd.k, c->kbd.nk); 541 if(ch > 0){ 542 c->kbd.alting = 0; 543 kputc(c, ch); 544 c->kbd.nk = 0; 545 qunlock(&c->eventlk); 546 return; 547 } 548 if(ch == -1){ 549 c->kbd.alting = 0; 550 for(i=0; i<c->kbd.nk; i++) 551 kputc(c, c->kbd.k[i]); 552 c->kbd.nk = 0; 553 qunlock(&c->eventlk); 554 return; 555 } 556 // need more input 557 qunlock(&c->eventlk); 558 return; 559 }