1implement Wmsrv; 2 3include "sys.m"; 4 sys: Sys; 5include "draw.m"; 6 draw: Draw; 7 Display, Image, Point, Rect, Screen, Pointer, Context, Wmcontext: import draw; 8include "wmsrv.m"; 9 10zorder: ref Client; # top of z-order list, linked by znext. 11 12ZR: con Rect((0, 0), (0, 0)); 13Iqueue: adt { 14 h, t: list of int; 15 n: int; 16 put: fn(q: self ref Iqueue, s: int); 17 get: fn(q: self ref Iqueue): int; 18 peek: fn(q: self ref Iqueue): int; 19 nonempty: fn(q: self ref Iqueue): int; 20}; 21Squeue: adt { 22 h, t: list of string; 23 n: int; 24 put: fn(q: self ref Squeue, s: string); 25 get: fn(q: self ref Squeue): string; 26 peek: fn(q: self ref Squeue): string; 27 nonempty: fn(q: self ref Squeue): int; 28}; 29# Ptrqueue is the same as the other queues except it merges events 30# that have the same button state. 31Ptrqueue: adt { 32 last: ref Pointer; 33 h, t: list of ref Pointer; 34 put: fn(q: self ref Ptrqueue, s: ref Pointer); 35 get: fn(q: self ref Ptrqueue): ref Pointer; 36 peek: fn(q: self ref Ptrqueue): ref Pointer; 37 nonempty: fn(q: self ref Ptrqueue): int; 38 flush: fn(q: self ref Ptrqueue); 39}; 40 41init(): (chan of (string, chan of (string, ref Wmcontext)), 42 chan of (ref Client, chan of string), 43 chan of (ref Client, array of byte, Sys->Rwrite)) 44{ 45 sys = load Sys Sys->PATH; 46 draw = load Draw Draw->PATH; 47 48 sys->bind("#s", "/chan", Sys->MBEFORE); 49 50 ctlio := sys->file2chan("/chan", "wmctl"); 51 if(ctlio == nil){ 52 sys->werrstr(sys->sprint("can't create /chan/wmctl: %r")); 53 return (nil, nil, nil); 54 } 55 56 wmreq := chan of (string, chan of (string, ref Wmcontext)); 57 join := chan of (ref Client, chan of string); 58 req := chan of (ref Client, array of byte, Sys->Rwrite); 59 spawn wm(ctlio, wmreq, join, req); 60 return (wmreq, join, req); 61} 62 63wm(ctlio: ref Sys->FileIO, 64 wmreq: chan of (string, chan of (string, ref Wmcontext)), 65 join: chan of (ref Client, chan of string), 66 req: chan of (ref Client, array of byte, Sys->Rwrite)) 67{ 68 clients: array of ref Client; 69 70 for(;;)alt{ 71 (cmd, rc) := <-wmreq => 72 token := int cmd; 73 for(i := 0; i < len clients; i++) 74 if(clients[i] != nil && clients[i].token == token) 75 break; 76 77 if(i == len clients){ 78 spawn senderror(rc, "not found"); 79 break; 80 } 81 c := clients[i]; 82 if(c.stop != nil){ 83 spawn senderror(rc, "already started"); 84 break; 85 } 86 ok := chan of string; 87 join <-= (c, ok); 88 if((e := <-ok) != nil){ 89 spawn senderror(rc, e); 90 break; 91 } 92 c.stop = chan of int; 93 spawn childminder(c, rc); 94 95 (nil, nbytes, fid, rc) := <-ctlio.read => 96 if(rc == nil) 97 break; 98 c := findfid(clients, fid); 99 if(c == nil){ 100 c = ref Client( 101 chan of int, 102 chan of ref Draw->Pointer, 103 chan of string, 104 nil, 105 0, 106 nil, 107 nil, 108 nil, 109 110 chan of (ref Point, ref Image, chan of int), 111 -1, 112 fid, 113 fid, # token; XXX could be random integer + fid 114 newwmcontext() 115 ); 116 clients = addclient(clients, c); 117 } 118 alt{ 119 rc <-= (sys->aprint("%d", c.token), nil) => ; 120 * => ; 121 } 122 (nil, data, fid, wc) := <-ctlio.write => 123 c := findfid(clients, fid); 124 if(wc != nil){ 125 if(c == nil){ 126 alt{ 127 wc <-= (0, "must read first") => ; 128 * => ; 129 } 130 break; 131 } 132 req <-= (c, data, wc); 133 }else if(c != nil){ 134 req <-= (c, nil, nil); 135 delclient(clients, c); 136 } 137 } 138} 139 140# buffer all events between a window manager and 141# a client, so that one recalcitrant child can't 142# clog the whole system. 143childminder(c: ref Client, rc: chan of (string, ref Wmcontext)) 144{ 145 wmctxt := c.wmctxt; 146 147 dummykbd := chan of int; 148 dummyptr := chan of ref Pointer; 149 dummyimg := chan of ref Image; 150 dummyctl := chan of string; 151 152 kbdq := ref Iqueue; 153 ptrq := ref Ptrqueue; 154 ctlq := ref Squeue; 155 156 Imgnone, Imgsend, Imgsendnil1, Imgsendnil2, Imgorigin: con iota; 157 img, sendimg: ref Image; 158 imgorigin: Point; 159 imgstate := Imgnone; 160 161 # send reply to client, but make sure we don't block. 162Reply: 163 for(;;) alt{ 164 rc <-= (nil, ref *wmctxt) => 165 break Reply; 166 <-c.stop => 167 exit; 168 key := <-c.kbd => 169 kbdq.put(key); 170 ptr := <-c.ptr => 171 ptrq.put(ptr); 172 ctl := <-c.ctl => 173 ctlq.put(ctl); 174 } 175 176 for(;;){ 177 outkbd := dummykbd; 178 key := -1; 179 if(kbdq.nonempty()){ 180 key = kbdq.peek(); 181 outkbd = wmctxt.kbd; 182 } 183 184 outptr := dummyptr; 185 ptr: ref Pointer; 186 if(ptrq.nonempty()){ 187 ptr = ptrq.peek(); 188 outptr = wmctxt.ptr; 189 } 190 191 outctl := dummyctl; 192 ctl: string; 193 if(ctlq.nonempty()){ 194 ctl = ctlq.peek(); 195 outctl = wmctxt.ctl; 196 } 197 198 outimg := dummyimg; 199 case imgstate{ 200 Imgsend => 201 outimg = wmctxt.images; 202 sendimg = img; 203 Imgsendnil1 or 204 Imgsendnil2 or 205 Imgorigin => 206 outimg = wmctxt.images; 207 sendimg = nil; 208 } 209 210 alt{ 211 outkbd <-= key => 212 kbdq.get(); 213 outptr <-= ptr => 214 ptrq.get(); 215 outctl <-= ctl => 216 ctlq.get(); 217 outimg <-= sendimg => 218 case imgstate{ 219 Imgsend => 220 imgstate = Imgnone; 221 img = sendimg = nil; 222 Imgsendnil1 => 223 imgstate = Imgsendnil2; 224 Imgsendnil2 => 225 imgstate = Imgnone; 226 Imgorigin => 227 if(img.origin(imgorigin, imgorigin) == -1){ 228 # XXX what can we do about this? there's no way at the moment 229 # of getting the information about the origin failure back to the wm, 230 # so we end up with an inconsistent window position. 231 # if the window manager blocks while we got the sync from 232 # the client, then a client could block the whole window manager 233 # which is what we're trying to avoid. 234 # but there's no other time we could set the origin of the window, 235 # and not risk mucking up the window contents. 236 # the short answer is that running out of image space is Bad News. 237 } 238 imgstate = Imgsend; 239 } 240 241 # XXX could mark the application as unresponding if any of these queues 242 # start growing too much. 243 ch := <-c.kbd => 244 kbdq.put(ch); 245 p := <-c.ptr => 246 if(p == nil) 247 ptrq.flush(); 248 else 249 ptrq.put(p); 250 e := <-c.ctl => 251 ctlq.put(e); 252 (o, i, reply) := <-c.images => 253 # can't queue multiple image requests. 254 if(imgstate != Imgnone) 255 reply <-= -1; 256 else { 257 # if the origin is being set, then we first send a nil image 258 # to indicate that this is happening, and then the 259 # image itself (reorigined). 260 # if a nil image is being set, then we 261 # send nil twice. 262 if(o != nil){ 263 imgorigin = *o; 264 imgstate = Imgorigin; 265 img = i; 266 }else if(i != nil){ 267 img = i; 268 imgstate = Imgsend; 269 }else 270 imgstate = Imgsendnil1; 271 reply <-= 0; 272 } 273 <-c.stop => 274 # XXX do we need to unblock channels, kill, etc.? 275 # we should perhaps drain the ctl output channel here 276 # if possible, exiting if it times out. 277 exit; 278 } 279 } 280} 281 282findfid(clients: array of ref Client, fid: int): ref Client 283{ 284 for(i := 0; i < len clients; i++) 285 if(clients[i] != nil && clients[i].fid == fid) 286 return clients[i]; 287 return nil; 288} 289 290addclient(clients: array of ref Client, c: ref Client): array of ref Client 291{ 292 for(i := 0; i < len clients; i++) 293 if(clients[i] == nil){ 294 clients[i] = c; 295 c.id = i; 296 return clients; 297 } 298 nc := array[len clients + 4] of ref Client; 299 nc[0:] = clients; 300 nc[len clients] = c; 301 c.id = len clients; 302 return nc; 303} 304 305delclient(clients: array of ref Client, c: ref Client) 306{ 307 clients[c.id] = nil; 308} 309 310senderror(rc: chan of (string, ref Wmcontext), e: string) 311{ 312 rc <-= (e, nil); 313} 314 315Client.window(c: self ref Client, tag: string): ref Window 316{ 317 for (w := c.wins; w != nil; w = tl w) 318 if((hd w).tag == tag) 319 return hd w; 320 return nil; 321} 322 323Client.image(c: self ref Client, tag: string): ref Draw->Image 324{ 325 w := c.window(tag); 326 if(w != nil) 327 return w.img; 328 return nil; 329} 330 331Client.setimage(c: self ref Client, tag: string, img: ref Draw->Image): int 332{ 333 # if img is nil, remove window from list. 334 if(img == nil){ 335 # usual case: 336 if(c.wins != nil && (hd c.wins).tag == tag){ 337 c.wins = tl c.wins; 338 return -1; 339 } 340 nw: list of ref Window; 341 for (w := c.wins; w != nil; w = tl w) 342 if((hd w).tag != tag) 343 nw = hd w :: nw; 344 c.wins = nil; 345 for(; nw != nil; nw = tl nw) 346 c.wins = hd nw :: c.wins; 347 return -1; 348 } 349 for(w := c.wins; w != nil; w = tl w) 350 if((hd w).tag == tag) 351 break; 352 win: ref Window; 353 if(w != nil) 354 win = hd w; 355 else{ 356 win = ref Window(tag, ZR, nil); 357 c.wins = win :: c.wins; 358 } 359 win.img = img; 360 win.r = img.r; # save so clients can set logical origin 361 rc := chan of int; 362 c.images <-= (nil, img, rc); 363 return <-rc; 364} 365 366# tell a client about a window that's moved to screen coord o. 367Client.setorigin(c: self ref Client, tag: string, o: Draw->Point): int 368{ 369 w := c.window(tag); 370 if(w == nil) 371 return -1; 372 img := w.img; 373 if(img == nil) 374 return -1; 375 rc := chan of int; 376 c.images <-= (ref o, w.img, rc); 377 if(<-rc != -1){ 378 w.r = (o, o.add(img.r.size())); 379 return 0; 380 } 381 return -1; 382} 383 384clientimages(c: ref Client): array of ref Image 385{ 386 a := array[len c.wins] of ref Draw->Image; 387 i := 0; 388 for(w := c.wins; w != nil; w = tl w) 389 if((hd w).img != nil) 390 a[i++] = (hd w).img; 391 return a[0:i]; 392} 393 394Client.top(c: self ref Client) 395{ 396 imgs := clientimages(c); 397 if(len imgs > 0) 398 imgs[0].screen.top(imgs); 399 400 if(zorder == c) 401 return; 402 403 prev: ref Client; 404 for(z := zorder; z != nil; (prev, z) = (z, z.znext)) 405 if(z == c) 406 break; 407 if(prev != nil) 408 prev.znext = c.znext; 409 c.znext = zorder; 410 zorder = c; 411} 412 413Client.bottom(c: self ref Client) 414{ 415 if(c.znext == nil) 416 return; 417 imgs := clientimages(c); 418 if(len imgs > 0) 419 imgs[0].screen.bottom(imgs); 420 prev: ref Client; 421 for(z := zorder; z != nil; (prev, z) = (z, z.znext)) 422 if(z == c) 423 break; 424 if(prev != nil) 425 prev.znext = c.znext; 426 else 427 zorder = c.znext; 428 z = c.znext; 429 c.znext = nil; 430 for(; z != nil; (prev, z) = (z, z.znext)) 431 ; 432 if(prev != nil) 433 prev.znext = c; 434 else 435 zorder = c; 436} 437 438Client.hide(nil: self ref Client) 439{ 440} 441 442Client.unhide(nil: self ref Client) 443{ 444} 445 446Client.remove(c: self ref Client) 447{ 448 prev: ref Client; 449 for(z := zorder; z != nil; (prev, z) = (z, z.znext)) 450 if(z == c) 451 break; 452 if(z == nil) 453 return; 454 if(prev != nil) 455 prev.znext = z.znext; 456 else if(z != nil) 457 zorder = zorder.znext; 458} 459 460find(p: Draw->Point): ref Client 461{ 462 for(z := zorder; z != nil; z = z.znext) 463 if(z.contains(p)) 464 return z; 465 return nil; 466} 467 468top(): ref Client 469{ 470 return zorder; 471} 472 473Client.contains(c: self ref Client, p: Point): int 474{ 475 for(w := c.wins; w != nil; w = tl w) 476 if((hd w).r.contains(p)) 477 return 1; 478 return 0; 479} 480 481r2s(r: Rect): string 482{ 483 return string r.min.x + " " + string r.min.y + " " + 484 string r.max.x + " " + string r.max.y; 485} 486 487newwmcontext(): ref Wmcontext 488{ 489 return ref Wmcontext( 490 chan of int, 491 chan of ref Pointer, 492 chan of string, 493 nil, 494 chan of ref Image, 495 nil, 496 nil 497 ); 498} 499 500Iqueue.put(q: self ref Iqueue, s: int) 501{ 502 q.t = s :: q.t; 503} 504Iqueue.get(q: self ref Iqueue): int 505{ 506 s := -1; 507 if(q.h == nil){ 508 for(t := q.t; t != nil; t = tl t) 509 q.h = hd t :: q.h; 510 q.t = nil; 511 } 512 if(q.h != nil){ 513 s = hd q.h; 514 q.h = tl q.h; 515 } 516 return s; 517} 518Iqueue.peek(q: self ref Iqueue): int 519{ 520 s := -1; 521 if (q.h == nil && q.t == nil) 522 return s; 523 s = q.get(); 524 q.h = s :: q.h; 525 return s; 526} 527Iqueue.nonempty(q: self ref Iqueue): int 528{ 529 return q.h != nil || q.t != nil; 530} 531 532 533Squeue.put(q: self ref Squeue, s: string) 534{ 535 q.t = s :: q.t; 536} 537Squeue.get(q: self ref Squeue): string 538{ 539 s: string; 540 if(q.h == nil){ 541 for(t := q.t; t != nil; t = tl t) 542 q.h = hd t :: q.h; 543 q.t = nil; 544 } 545 if(q.h != nil){ 546 s = hd q.h; 547 q.h = tl q.h; 548 } 549 return s; 550} 551Squeue.peek(q: self ref Squeue): string 552{ 553 s: string; 554 if (q.h == nil && q.t == nil) 555 return s; 556 s = q.get(); 557 q.h = s :: q.h; 558 return s; 559} 560Squeue.nonempty(q: self ref Squeue): int 561{ 562 return q.h != nil || q.t != nil; 563} 564 565Ptrqueue.put(q: self ref Ptrqueue, s: ref Pointer) 566{ 567 if(q.last != nil && s.buttons == q.last.buttons) 568 *q.last = *s; 569 else{ 570 q.t = s :: q.t; 571 q.last = s; 572 } 573} 574Ptrqueue.get(q: self ref Ptrqueue): ref Pointer 575{ 576 s: ref Pointer; 577 h := q.h; 578 if(h == nil){ 579 for(t := q.t; t != nil; t = tl t) 580 h = hd t :: h; 581 q.t = nil; 582 } 583 if(h != nil){ 584 s = hd h; 585 h = tl h; 586 if(h == nil) 587 q.last = nil; 588 } 589 q.h = h; 590 return s; 591} 592Ptrqueue.peek(q: self ref Ptrqueue): ref Pointer 593{ 594 s: ref Pointer; 595 if (q.h == nil && q.t == nil) 596 return s; 597 t := q.last; 598 s = q.get(); 599 q.h = s :: q.h; 600 q.last = t; 601 return s; 602} 603Ptrqueue.nonempty(q: self ref Ptrqueue): int 604{ 605 return q.h != nil || q.t != nil; 606} 607Ptrqueue.flush(q: self ref Ptrqueue) 608{ 609 q.h = q.t = nil; 610} 611