1*37da2899SCharles.Forsythimplement Wmlib; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsyth# 4*37da2899SCharles.Forsyth# Copyright © 2003 Vita Nuova Holdings Limited 5*37da2899SCharles.Forsyth# 6*37da2899SCharles.Forsyth 7*37da2899SCharles.Forsyth# basic window manager functionality, used by 8*37da2899SCharles.Forsyth# tkclient and wmclient to create more usable functionality. 9*37da2899SCharles.Forsyth 10*37da2899SCharles.Forsythinclude "sys.m"; 11*37da2899SCharles.Forsyth sys: Sys; 12*37da2899SCharles.Forsythinclude "draw.m"; 13*37da2899SCharles.Forsyth draw: Draw; 14*37da2899SCharles.Forsyth Display, Image, Screen, Rect, Point, Pointer, Wmcontext, Context: import draw; 15*37da2899SCharles.Forsythinclude "wmsrv.m"; 16*37da2899SCharles.Forsythinclude "wmlib.m"; 17*37da2899SCharles.Forsyth 18*37da2899SCharles.ForsythClient: adt{ 19*37da2899SCharles.Forsyth ptrpid: int; 20*37da2899SCharles.Forsyth kbdpid: int; 21*37da2899SCharles.Forsyth ctlpid: int; 22*37da2899SCharles.Forsyth req: chan of (array of byte, Sys->Rwrite); 23*37da2899SCharles.Forsyth dir: string; 24*37da2899SCharles.Forsyth ctlfd: ref Sys->FD; 25*37da2899SCharles.Forsyth winfd: ref Sys->FD; 26*37da2899SCharles.Forsyth}; 27*37da2899SCharles.Forsyth 28*37da2899SCharles.ForsythDEVWM: con "/mnt/wm"; 29*37da2899SCharles.ForsythPtrsize: con 1+4*12; # 'm' plus 4 12-byte decimal integers 30*37da2899SCharles.Forsyth 31*37da2899SCharles.Forsythkbdstarted: int; 32*37da2899SCharles.Forsythptrstarted: int; 33*37da2899SCharles.Forsythwptr: chan of Point; # set mouse position (only if we've opened /dev/pointer directly) 34*37da2899SCharles.Forsythcswitch: chan of (string, int, chan of string); # switch cursor images (as for wptr) 35*37da2899SCharles.Forsyth 36*37da2899SCharles.Forsythinit() 37*37da2899SCharles.Forsyth{ 38*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 39*37da2899SCharles.Forsyth draw = load Draw Draw->PATH; 40*37da2899SCharles.Forsyth} 41*37da2899SCharles.Forsyth 42*37da2899SCharles.Forsyth# (_screen, dispi) := ctxt.display.getwindow("/dev/winname", nil, nil, 1); XXX corrupts heap... fix it! 43*37da2899SCharles.Forsyth 44*37da2899SCharles.Forsythmakedrawcontext(): ref Draw->Context 45*37da2899SCharles.Forsyth{ 46*37da2899SCharles.Forsyth display := Display.allocate(nil); 47*37da2899SCharles.Forsyth if(display == nil){ 48*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "wmlib: can't allocate Display: %r\n"); 49*37da2899SCharles.Forsyth raise "fail:no display"; 50*37da2899SCharles.Forsyth } 51*37da2899SCharles.Forsyth return ref Draw->Context(display, nil, nil); 52*37da2899SCharles.Forsyth} 53*37da2899SCharles.Forsyth 54*37da2899SCharles.Forsythimportdrawcontext(devdraw, mntwm: string): (ref Draw->Context, string) 55*37da2899SCharles.Forsyth{ 56*37da2899SCharles.Forsyth if(mntwm == nil) 57*37da2899SCharles.Forsyth mntwm = "/mnt/wm"; 58*37da2899SCharles.Forsyth 59*37da2899SCharles.Forsyth display := Display.allocate(devdraw); 60*37da2899SCharles.Forsyth if(display == nil) 61*37da2899SCharles.Forsyth return (nil, sys->sprint("cannot allocate display: %r")); 62*37da2899SCharles.Forsyth (ok, nil) := sys->stat(mntwm + "/clone"); 63*37da2899SCharles.Forsyth if(ok == -1) 64*37da2899SCharles.Forsyth return (nil, "cannot find wm namespace"); 65*37da2899SCharles.Forsyth wc := chan of (ref Draw->Context, string); 66*37da2899SCharles.Forsyth spawn wmproxy(display, mntwm, wc); 67*37da2899SCharles.Forsyth return <-wc; 68*37da2899SCharles.Forsyth} 69*37da2899SCharles.Forsyth 70*37da2899SCharles.Forsyth# XXX we have no way of knowing when this process should go away... 71*37da2899SCharles.Forsyth# perhaps a Draw->Context should hold a file descriptor 72*37da2899SCharles.Forsyth# so that we do. 73*37da2899SCharles.Forsythwmproxy(display: ref Display, dir: string, wc: chan of (ref Draw->Context, string)) 74*37da2899SCharles.Forsyth{ 75*37da2899SCharles.Forsyth wmsrv := load Wmsrv Wmsrv->PATH; 76*37da2899SCharles.Forsyth if(wmsrv == nil){ 77*37da2899SCharles.Forsyth wc <-= (nil, sys->sprint("cannot load %s: %r", Wmsrv->PATH)); 78*37da2899SCharles.Forsyth return; 79*37da2899SCharles.Forsyth } 80*37da2899SCharles.Forsyth sys->pctl(Sys->NEWFD, 1 :: 2 :: nil); 81*37da2899SCharles.Forsyth 82*37da2899SCharles.Forsyth (wm, join, req) := wmsrv->init(); 83*37da2899SCharles.Forsyth if(wm == nil){ 84*37da2899SCharles.Forsyth wc <-= (nil, sys->sprint("%r")); 85*37da2899SCharles.Forsyth return; 86*37da2899SCharles.Forsyth } 87*37da2899SCharles.Forsyth wc <-= (ref Draw->Context(display, nil, wm), nil); 88*37da2899SCharles.Forsyth 89*37da2899SCharles.Forsyth clients: array of ref Client; 90*37da2899SCharles.Forsyth for(;;) alt{ 91*37da2899SCharles.Forsyth (sc, rc) := <-join => 92*37da2899SCharles.Forsyth sync := chan of (ref Client, string); 93*37da2899SCharles.Forsyth spawn clientproc(display, sc, dir, sync); 94*37da2899SCharles.Forsyth (c, err) := <-sync; 95*37da2899SCharles.Forsyth rc <-= err; 96*37da2899SCharles.Forsyth if(c != nil){ 97*37da2899SCharles.Forsyth if(sc.id >= len clients) 98*37da2899SCharles.Forsyth clients = (array[sc.id + 1] of ref Client)[0:] = clients; 99*37da2899SCharles.Forsyth clients[sc.id] = c; 100*37da2899SCharles.Forsyth } 101*37da2899SCharles.Forsyth (sc, data, rc) := <-req => 102*37da2899SCharles.Forsyth clients[sc.id].req <-= (data, rc); 103*37da2899SCharles.Forsyth if(rc == nil) 104*37da2899SCharles.Forsyth clients[sc.id] = nil; 105*37da2899SCharles.Forsyth } 106*37da2899SCharles.Forsyth} 107*37da2899SCharles.Forsyth 108*37da2899SCharles.Forsythzclient: Client; 109*37da2899SCharles.Forsythclientproc(display: ref Display, sc: ref Wmsrv->Client, dir: string, rc: chan of (ref Client, string)) 110*37da2899SCharles.Forsyth{ 111*37da2899SCharles.Forsyth ctlfd := sys->open(dir + "/clone", Sys->ORDWR); 112*37da2899SCharles.Forsyth if(ctlfd == nil){ 113*37da2899SCharles.Forsyth rc <-= (nil, sys->sprint("cannot open %s/clone: %r", dir)); 114*37da2899SCharles.Forsyth return; 115*37da2899SCharles.Forsyth } 116*37da2899SCharles.Forsyth buf := array[20] of byte; 117*37da2899SCharles.Forsyth n := sys->read(ctlfd, buf, len buf); 118*37da2899SCharles.Forsyth if(n <= 0){ 119*37da2899SCharles.Forsyth rc <-= (nil, "cannot read ctl id"); 120*37da2899SCharles.Forsyth return; 121*37da2899SCharles.Forsyth } 122*37da2899SCharles.Forsyth sys->fprint(ctlfd, "fixedorigin"); 123*37da2899SCharles.Forsyth dir += "/" + string buf[0:n]; 124*37da2899SCharles.Forsyth c := ref zclient; 125*37da2899SCharles.Forsyth c.req = chan of (array of byte, Sys->Rwrite); 126*37da2899SCharles.Forsyth c.dir = dir; 127*37da2899SCharles.Forsyth c.ctlfd = ctlfd; 128*37da2899SCharles.Forsyth if ((c.winfd = sys->open(dir + "/winname", Sys->OREAD)) == nil){ 129*37da2899SCharles.Forsyth rc <-= (nil, sys->sprint("cannot open %s/winname: %r", dir)); 130*37da2899SCharles.Forsyth return; 131*37da2899SCharles.Forsyth } 132*37da2899SCharles.Forsyth rc <-= (c, nil); 133*37da2899SCharles.Forsyth 134*37da2899SCharles.Forsyth pidc := chan of int; 135*37da2899SCharles.Forsyth spawn ctlproc(pidc, ctlfd, sc.ctl); 136*37da2899SCharles.Forsyth c.ctlpid = <-pidc; 137*37da2899SCharles.Forsyth for(;;) { 138*37da2899SCharles.Forsyth (data, drc) := <-c.req; 139*37da2899SCharles.Forsyth if(drc == nil) 140*37da2899SCharles.Forsyth break; 141*37da2899SCharles.Forsyth err := handlerequest(display, c, sc, data); 142*37da2899SCharles.Forsyth n = len data; 143*37da2899SCharles.Forsyth if(err != nil) 144*37da2899SCharles.Forsyth n = -1; 145*37da2899SCharles.Forsyth alt{ 146*37da2899SCharles.Forsyth drc <-= (n, err) =>; 147*37da2899SCharles.Forsyth * =>; 148*37da2899SCharles.Forsyth } 149*37da2899SCharles.Forsyth } 150*37da2899SCharles.Forsyth sc.stop <-= 1; 151*37da2899SCharles.Forsyth kill(c.kbdpid, "kill"); 152*37da2899SCharles.Forsyth kill(c.ptrpid, "kill"); 153*37da2899SCharles.Forsyth kill(c.ctlpid, "kill"); 154*37da2899SCharles.Forsyth c.ctlfd = nil; 155*37da2899SCharles.Forsyth c.winfd = nil; 156*37da2899SCharles.Forsyth} 157*37da2899SCharles.Forsyth 158*37da2899SCharles.Forsythhandlerequest(display: ref Display, c: ref Client, sc: ref Wmsrv->Client, data: array of byte): string 159*37da2899SCharles.Forsyth{ 160*37da2899SCharles.Forsyth req := string data; 161*37da2899SCharles.Forsyth if(req == nil) 162*37da2899SCharles.Forsyth return nil; 163*37da2899SCharles.Forsyth (w, e) := qword(req, 0); 164*37da2899SCharles.Forsyth case w { 165*37da2899SCharles.Forsyth "start" => 166*37da2899SCharles.Forsyth (w, e) = qword(req, e); 167*37da2899SCharles.Forsyth case w { 168*37da2899SCharles.Forsyth "ptr" or 169*37da2899SCharles.Forsyth "mouse" => 170*37da2899SCharles.Forsyth if(c.ptrpid == -1) 171*37da2899SCharles.Forsyth return "already started"; 172*37da2899SCharles.Forsyth fd := sys->open(c.dir + "/pointer", Sys->OREAD); 173*37da2899SCharles.Forsyth if(fd == nil) 174*37da2899SCharles.Forsyth return sys->sprint("cannot open %s: %r", c.dir + "/pointer"); 175*37da2899SCharles.Forsyth sync := chan of int; 176*37da2899SCharles.Forsyth spawn ptrproc(sync, fd, sc.ptr); 177*37da2899SCharles.Forsyth c.ptrpid = <-sync; 178*37da2899SCharles.Forsyth return nil; 179*37da2899SCharles.Forsyth "kbd" => 180*37da2899SCharles.Forsyth if(c.kbdpid == -1) 181*37da2899SCharles.Forsyth return "already started"; 182*37da2899SCharles.Forsyth sync := chan of (int, string); 183*37da2899SCharles.Forsyth spawn kbdproc(sync, c.dir + "/keyboard", sc.kbd); 184*37da2899SCharles.Forsyth (pid, err) := <-sync; 185*37da2899SCharles.Forsyth c.kbdpid = pid; 186*37da2899SCharles.Forsyth return err; 187*37da2899SCharles.Forsyth } 188*37da2899SCharles.Forsyth } 189*37da2899SCharles.Forsyth 190*37da2899SCharles.Forsyth if(sys->write(c.ctlfd, data, len data) == -1) 191*37da2899SCharles.Forsyth return sys->sprint("%r"); 192*37da2899SCharles.Forsyth if(req[0] == '!'){ 193*37da2899SCharles.Forsyth buf := array[100] of byte; 194*37da2899SCharles.Forsyth n := sys->read(c.winfd, buf, len buf); 195*37da2899SCharles.Forsyth if(n <= 0) 196*37da2899SCharles.Forsyth return sys->sprint("read winname: %r"); 197*37da2899SCharles.Forsyth name := string buf[0:n]; 198*37da2899SCharles.Forsyth # XXX this is the dodgy bit... 199*37da2899SCharles.Forsyth i := display.namedimage(name); 200*37da2899SCharles.Forsyth if(i == nil) 201*37da2899SCharles.Forsyth return sys->sprint("cannot get image %#q: %r", name); 202*37da2899SCharles.Forsyth s := Screen.allocate(i, display.white, 0); 203*37da2899SCharles.Forsyth i = s.newwindow(i.r, Draw->Refnone, Draw->Nofill); 204*37da2899SCharles.Forsyth rc := chan of int; 205*37da2899SCharles.Forsyth sc.images <-= (nil, i, rc); 206*37da2899SCharles.Forsyth if(<-rc == -1) 207*37da2899SCharles.Forsyth return "image request already in progress"; 208*37da2899SCharles.Forsyth } 209*37da2899SCharles.Forsyth return nil; 210*37da2899SCharles.Forsyth} 211*37da2899SCharles.Forsyth 212*37da2899SCharles.Forsythconnect(ctxt: ref Context): ref Wmcontext 213*37da2899SCharles.Forsyth{ 214*37da2899SCharles.Forsyth # don't automatically make a new Draw->Context, 'cos the 215*37da2899SCharles.Forsyth # client should be aware that there's no wm so multiple 216*37da2899SCharles.Forsyth # windows won't work correctly. 217*37da2899SCharles.Forsyth # ... unless there's an exported wm available, of course! 218*37da2899SCharles.Forsyth if(ctxt == nil){ 219*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "wmlib: no draw context\n"); 220*37da2899SCharles.Forsyth raise "fail:error"; 221*37da2899SCharles.Forsyth } 222*37da2899SCharles.Forsyth if(ctxt.wm == nil){ 223*37da2899SCharles.Forsyth wm := ref Wmcontext( 224*37da2899SCharles.Forsyth chan of int, 225*37da2899SCharles.Forsyth chan of ref Draw->Pointer, 226*37da2899SCharles.Forsyth chan of string, 227*37da2899SCharles.Forsyth nil, # unused 228*37da2899SCharles.Forsyth chan of ref Image, 229*37da2899SCharles.Forsyth nil, 230*37da2899SCharles.Forsyth ctxt 231*37da2899SCharles.Forsyth ); 232*37da2899SCharles.Forsyth return wm; 233*37da2899SCharles.Forsyth } 234*37da2899SCharles.Forsyth fd := sys->open("/chan/wmctl", Sys->ORDWR); 235*37da2899SCharles.Forsyth if(fd == nil){ 236*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "wmlib: cannot open /chan/wmctl: %r\n"); 237*37da2899SCharles.Forsyth raise "fail:error"; 238*37da2899SCharles.Forsyth } 239*37da2899SCharles.Forsyth buf := array[32] of byte; 240*37da2899SCharles.Forsyth n := sys->read(fd, buf, len buf); 241*37da2899SCharles.Forsyth if(n < 0){ 242*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "wmlib: cannot get window token: %r\n"); 243*37da2899SCharles.Forsyth raise "fail:error"; 244*37da2899SCharles.Forsyth } 245*37da2899SCharles.Forsyth reply := chan of (string, ref Wmcontext); 246*37da2899SCharles.Forsyth ctxt.wm <-= (string buf[0:n], reply); 247*37da2899SCharles.Forsyth (err, wm) := <-reply; 248*37da2899SCharles.Forsyth if(err != nil){ 249*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "wmlib: cannot connect: %s\n", err); 250*37da2899SCharles.Forsyth raise "fail:" + err; 251*37da2899SCharles.Forsyth } 252*37da2899SCharles.Forsyth wm.connfd = fd; 253*37da2899SCharles.Forsyth wm.ctxt = ctxt; 254*37da2899SCharles.Forsyth return wm; 255*37da2899SCharles.Forsyth} 256*37da2899SCharles.Forsyth 257*37da2899SCharles.Forsythstartinput(wm: ref Wmcontext, devs: list of string): string 258*37da2899SCharles.Forsyth{ 259*37da2899SCharles.Forsyth for(; devs != nil; devs = tl devs) 260*37da2899SCharles.Forsyth wmctl(wm, "start " + hd devs); 261*37da2899SCharles.Forsyth return nil; 262*37da2899SCharles.Forsyth} 263*37da2899SCharles.Forsyth 264*37da2899SCharles.Forsythreshape(wm: ref Wmcontext, name: string, r: Draw->Rect, i: ref Draw->Image, how: string): ref Draw->Image 265*37da2899SCharles.Forsyth{ 266*37da2899SCharles.Forsyth if(name == nil) 267*37da2899SCharles.Forsyth return nil; 268*37da2899SCharles.Forsyth (nil, ni, err) := wmctl(wm, sys->sprint("!reshape %s -1 %d %d %d %d %s", name, r.min.x, r.min.y, r.max.x, r.max.y, how)); 269*37da2899SCharles.Forsyth if(err == nil) 270*37da2899SCharles.Forsyth return ni; 271*37da2899SCharles.Forsyth return i; 272*37da2899SCharles.Forsyth} 273*37da2899SCharles.Forsyth 274*37da2899SCharles.Forsyth# 275*37da2899SCharles.Forsyth# wmctl implements the default window behaviour 276*37da2899SCharles.Forsyth# 277*37da2899SCharles.Forsythwmctl(wm: ref Wmcontext, request: string): (string, ref Image, string) 278*37da2899SCharles.Forsyth{ 279*37da2899SCharles.Forsyth (w, e) := qword(request, 0); 280*37da2899SCharles.Forsyth case w { 281*37da2899SCharles.Forsyth "exit" => 282*37da2899SCharles.Forsyth kill(sys->pctl(0, nil), "killgrp"); 283*37da2899SCharles.Forsyth exit; 284*37da2899SCharles.Forsyth * => 285*37da2899SCharles.Forsyth if(wm.connfd != nil){ 286*37da2899SCharles.Forsyth # standard form for requests: if request starts with '!', 287*37da2899SCharles.Forsyth # then the next word gives the tag of the window that the 288*37da2899SCharles.Forsyth # request applies to, and a new image is provided. 289*37da2899SCharles.Forsyth if(sys->fprint(wm.connfd, "%s", request) == -1){ 290*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "wmlib: wm request '%s' failed\n", request); 291*37da2899SCharles.Forsyth return (nil, nil, sys->sprint("%r")); 292*37da2899SCharles.Forsyth } 293*37da2899SCharles.Forsyth if(request[0] == '!'){ 294*37da2899SCharles.Forsyth i := <-wm.images; 295*37da2899SCharles.Forsyth if(i == nil) 296*37da2899SCharles.Forsyth i = <-wm.images; 297*37da2899SCharles.Forsyth return (qword(request, e).t0, i, nil); 298*37da2899SCharles.Forsyth } 299*37da2899SCharles.Forsyth return (nil, nil, nil); 300*37da2899SCharles.Forsyth } 301*37da2899SCharles.Forsyth # requests we can handle ourselves, if we have to. 302*37da2899SCharles.Forsyth case w{ 303*37da2899SCharles.Forsyth "start" => 304*37da2899SCharles.Forsyth (w, e) = qword(request, e); 305*37da2899SCharles.Forsyth case w{ 306*37da2899SCharles.Forsyth "ptr" or 307*37da2899SCharles.Forsyth "mouse" => 308*37da2899SCharles.Forsyth if(!ptrstarted){ 309*37da2899SCharles.Forsyth fd := sys->open("/dev/pointer", Sys->ORDWR); 310*37da2899SCharles.Forsyth if(fd != nil) 311*37da2899SCharles.Forsyth wptr = chan of Point; 312*37da2899SCharles.Forsyth else 313*37da2899SCharles.Forsyth fd = sys->open("/dev/pointer", Sys->OREAD); 314*37da2899SCharles.Forsyth if(fd == nil) 315*37da2899SCharles.Forsyth return (nil, nil, sys->sprint("cannot open /dev/pointer: %r")); 316*37da2899SCharles.Forsyth cfd := sys->open("/dev/cursor", Sys->OWRITE); 317*37da2899SCharles.Forsyth if(cfd != nil) 318*37da2899SCharles.Forsyth cswitch = chan of (string, int, chan of string); 319*37da2899SCharles.Forsyth spawn wptrproc(fd, cfd); 320*37da2899SCharles.Forsyth sync := chan of int; 321*37da2899SCharles.Forsyth spawn ptrproc(sync, fd, wm.ptr); 322*37da2899SCharles.Forsyth <-sync; 323*37da2899SCharles.Forsyth ptrstarted = 1; 324*37da2899SCharles.Forsyth } 325*37da2899SCharles.Forsyth "kbd" => 326*37da2899SCharles.Forsyth if(!kbdstarted){ 327*37da2899SCharles.Forsyth sync := chan of (int, string); 328*37da2899SCharles.Forsyth spawn kbdproc(sync, "/dev/keyboard", wm.kbd); 329*37da2899SCharles.Forsyth (nil, err) := <-sync; 330*37da2899SCharles.Forsyth if(err != nil) 331*37da2899SCharles.Forsyth return (nil, nil, err); 332*37da2899SCharles.Forsyth spawn sendreq(wm.ctl, "haskbdfocus 1"); 333*37da2899SCharles.Forsyth kbdstarted = 1; 334*37da2899SCharles.Forsyth } 335*37da2899SCharles.Forsyth * => 336*37da2899SCharles.Forsyth return (nil, nil, "unknown input source"); 337*37da2899SCharles.Forsyth } 338*37da2899SCharles.Forsyth return (nil, nil, nil); 339*37da2899SCharles.Forsyth "ptr" => 340*37da2899SCharles.Forsyth if(wptr == nil) 341*37da2899SCharles.Forsyth return (nil, nil, "cannot change mouse position"); 342*37da2899SCharles.Forsyth p: Point; 343*37da2899SCharles.Forsyth (w, e) = qword(request, e); 344*37da2899SCharles.Forsyth p.x = int w; 345*37da2899SCharles.Forsyth (w, e) = qword(request, e); 346*37da2899SCharles.Forsyth p.y = int w; 347*37da2899SCharles.Forsyth wptr <-= p; 348*37da2899SCharles.Forsyth return (nil, nil, nil); 349*37da2899SCharles.Forsyth "cursor" => 350*37da2899SCharles.Forsyth if(cswitch == nil) 351*37da2899SCharles.Forsyth return (nil, nil, "cannot switch cursor"); 352*37da2899SCharles.Forsyth cswitch <-= (request, e, reply := chan of string); 353*37da2899SCharles.Forsyth return (nil, nil, <-reply); 354*37da2899SCharles.Forsyth * => 355*37da2899SCharles.Forsyth return (nil, nil, "unknown wmctl request"); 356*37da2899SCharles.Forsyth } 357*37da2899SCharles.Forsyth } 358*37da2899SCharles.Forsyth} 359*37da2899SCharles.Forsyth 360*37da2899SCharles.Forsythsendreq(c: chan of string, s: string) 361*37da2899SCharles.Forsyth{ 362*37da2899SCharles.Forsyth c <-= s; 363*37da2899SCharles.Forsyth} 364*37da2899SCharles.Forsyth 365*37da2899SCharles.Forsythctlproc(sync: chan of int, fd: ref Sys->FD, ctl: chan of string) 366*37da2899SCharles.Forsyth{ 367*37da2899SCharles.Forsyth sync <-= sys->pctl(0, nil); 368*37da2899SCharles.Forsyth buf := array[4096] of byte; 369*37da2899SCharles.Forsyth while((n := sys->read(fd, buf, len buf)) > 0) 370*37da2899SCharles.Forsyth ctl <-= string buf[0:n]; 371*37da2899SCharles.Forsyth} 372*37da2899SCharles.Forsyth 373*37da2899SCharles.Forsythkbdproc(sync: chan of (int, string), f: string, keys: chan of int) 374*37da2899SCharles.Forsyth{ 375*37da2899SCharles.Forsyth sys->pctl(Sys->NEWFD, nil); 376*37da2899SCharles.Forsyth fd := sys->open(f, Sys->OREAD); 377*37da2899SCharles.Forsyth if(fd == nil){ 378*37da2899SCharles.Forsyth sync <-= (-1, sys->sprint("cannot open /dev/keyboard: %r")); 379*37da2899SCharles.Forsyth return; 380*37da2899SCharles.Forsyth } 381*37da2899SCharles.Forsyth sync <-= (sys->pctl(0, nil), nil); 382*37da2899SCharles.Forsyth buf := array[12] of byte; 383*37da2899SCharles.Forsyth while((n := sys->read(fd, buf, len buf)) > 0){ 384*37da2899SCharles.Forsyth s := string buf[0:n]; 385*37da2899SCharles.Forsyth for(j := 0; j < len s; j++) 386*37da2899SCharles.Forsyth keys <-= int s[j]; 387*37da2899SCharles.Forsyth } 388*37da2899SCharles.Forsyth} 389*37da2899SCharles.Forsyth 390*37da2899SCharles.Forsythwptrproc(pfd, cfd: ref Sys->FD) 391*37da2899SCharles.Forsyth{ 392*37da2899SCharles.Forsyth if(wptr == nil && cswitch == nil) 393*37da2899SCharles.Forsyth return; 394*37da2899SCharles.Forsyth if(wptr == nil) 395*37da2899SCharles.Forsyth wptr = chan of Point; 396*37da2899SCharles.Forsyth if(cswitch == nil) 397*37da2899SCharles.Forsyth cswitch = chan of (string, int, chan of string); 398*37da2899SCharles.Forsyth for(;;)alt{ 399*37da2899SCharles.Forsyth p := <-wptr => 400*37da2899SCharles.Forsyth sys->fprint(pfd, "m%11d %11d", p.x, p.y); 401*37da2899SCharles.Forsyth (c, start, reply) := <-cswitch => 402*37da2899SCharles.Forsyth buf: array of byte; 403*37da2899SCharles.Forsyth if(start == len c){ 404*37da2899SCharles.Forsyth buf = array[0] of byte; 405*37da2899SCharles.Forsyth }else{ 406*37da2899SCharles.Forsyth hot, size: Point; 407*37da2899SCharles.Forsyth (w, e) := qword(c, start); 408*37da2899SCharles.Forsyth hot.x = int w; 409*37da2899SCharles.Forsyth (w, e) = qword(c, e); 410*37da2899SCharles.Forsyth hot.y = int w; 411*37da2899SCharles.Forsyth (w, e) = qword(c, e); 412*37da2899SCharles.Forsyth size.x = int w; 413*37da2899SCharles.Forsyth (w, e) = qword(c, e); 414*37da2899SCharles.Forsyth size.y = int w; 415*37da2899SCharles.Forsyth ((d0, d1), nil) := splitqword(c, e); 416*37da2899SCharles.Forsyth nb := size.x/8*size.y; 417*37da2899SCharles.Forsyth if(d1 - d0 != nb * 2){ 418*37da2899SCharles.Forsyth reply <-= "inconsistent cursor image data"; 419*37da2899SCharles.Forsyth break; 420*37da2899SCharles.Forsyth } 421*37da2899SCharles.Forsyth buf = array[4*4 + nb] of byte; 422*37da2899SCharles.Forsyth bplong(buf, 0*4, hot.x); 423*37da2899SCharles.Forsyth bplong(buf, 1*4, hot.y); 424*37da2899SCharles.Forsyth bplong(buf, 2*4, size.x); 425*37da2899SCharles.Forsyth bplong(buf, 3*4, size.y); 426*37da2899SCharles.Forsyth j := 4*4; 427*37da2899SCharles.Forsyth for(i := d0; i < d1; i += 2) 428*37da2899SCharles.Forsyth buf[j++] = byte ((hexc(c[i]) << 4) | hexc(c[i+1])); 429*37da2899SCharles.Forsyth } 430*37da2899SCharles.Forsyth if(sys->write(cfd, buf, len buf) != len buf) 431*37da2899SCharles.Forsyth reply <-= sys->sprint("%r"); 432*37da2899SCharles.Forsyth else 433*37da2899SCharles.Forsyth reply <-= nil; 434*37da2899SCharles.Forsyth } 435*37da2899SCharles.Forsyth} 436*37da2899SCharles.Forsyth 437*37da2899SCharles.Forsythhexc(c: int): int 438*37da2899SCharles.Forsyth{ 439*37da2899SCharles.Forsyth if(c >= '0' && c <= '9') 440*37da2899SCharles.Forsyth return c - '0'; 441*37da2899SCharles.Forsyth if(c >= 'a' && c <= 'f') 442*37da2899SCharles.Forsyth return c - 'a' + 10; 443*37da2899SCharles.Forsyth if(c >= 'A' && c <= 'F') 444*37da2899SCharles.Forsyth return c - 'A' + 10; 445*37da2899SCharles.Forsyth return 0; 446*37da2899SCharles.Forsyth} 447*37da2899SCharles.Forsyth 448*37da2899SCharles.Forsythbplong(d: array of byte, o: int, x: int) 449*37da2899SCharles.Forsyth{ 450*37da2899SCharles.Forsyth d[o] = byte x; 451*37da2899SCharles.Forsyth d[o+1] = byte (x >> 8); 452*37da2899SCharles.Forsyth d[o+2] = byte (x >> 16); 453*37da2899SCharles.Forsyth d[o+3] = byte (x >> 24); 454*37da2899SCharles.Forsyth} 455*37da2899SCharles.Forsyth 456*37da2899SCharles.Forsythptrproc(sync: chan of int, fd: ref Sys->FD, ptr: chan of ref Draw->Pointer) 457*37da2899SCharles.Forsyth{ 458*37da2899SCharles.Forsyth sync <-= sys->pctl(0, nil); 459*37da2899SCharles.Forsyth 460*37da2899SCharles.Forsyth b:= array[Ptrsize] of byte; 461*37da2899SCharles.Forsyth while(sys->read(fd, b, len b) > 0){ 462*37da2899SCharles.Forsyth p := bytes2ptr(b); 463*37da2899SCharles.Forsyth if(p != nil) 464*37da2899SCharles.Forsyth ptr <-= p; 465*37da2899SCharles.Forsyth } 466*37da2899SCharles.Forsyth} 467*37da2899SCharles.Forsyth 468*37da2899SCharles.Forsythbytes2ptr(b: array of byte): ref Pointer 469*37da2899SCharles.Forsyth{ 470*37da2899SCharles.Forsyth if(len b < Ptrsize || int b[0] != 'm') 471*37da2899SCharles.Forsyth return nil; 472*37da2899SCharles.Forsyth x := int string b[1:13]; 473*37da2899SCharles.Forsyth y := int string b[13:25]; 474*37da2899SCharles.Forsyth but := int string b[25:37]; 475*37da2899SCharles.Forsyth msec := int string b[37:49]; 476*37da2899SCharles.Forsyth return ref Pointer (but, (x, y), msec); 477*37da2899SCharles.Forsyth} 478*37da2899SCharles.Forsyth 479*37da2899SCharles.Forsythsnarfbuf: string; # at least we get *something* when there's no wm. 480*37da2899SCharles.Forsyth 481*37da2899SCharles.Forsythsnarfget(): string 482*37da2899SCharles.Forsyth{ 483*37da2899SCharles.Forsyth fd := sys->open("/chan/snarf", sys->OREAD); 484*37da2899SCharles.Forsyth if(fd == nil) 485*37da2899SCharles.Forsyth return snarfbuf; 486*37da2899SCharles.Forsyth 487*37da2899SCharles.Forsyth buf := array[8192] of byte; 488*37da2899SCharles.Forsyth nr := 0; 489*37da2899SCharles.Forsyth while ((n := sys->read(fd, buf[nr:], len buf - nr)) > 0) { 490*37da2899SCharles.Forsyth nr += n; 491*37da2899SCharles.Forsyth if (nr == len buf) { 492*37da2899SCharles.Forsyth nbuf := array[len buf * 2] of byte; 493*37da2899SCharles.Forsyth nbuf[0:] = buf; 494*37da2899SCharles.Forsyth buf = nbuf; 495*37da2899SCharles.Forsyth } 496*37da2899SCharles.Forsyth } 497*37da2899SCharles.Forsyth return string buf[0:nr]; 498*37da2899SCharles.Forsyth} 499*37da2899SCharles.Forsyth 500*37da2899SCharles.Forsythsnarfput(buf: string) 501*37da2899SCharles.Forsyth{ 502*37da2899SCharles.Forsyth fd := sys->open("/chan/snarf", sys->OWRITE); 503*37da2899SCharles.Forsyth if(fd != nil) 504*37da2899SCharles.Forsyth sys->fprint(fd, "%s", buf); 505*37da2899SCharles.Forsyth else 506*37da2899SCharles.Forsyth snarfbuf = buf; 507*37da2899SCharles.Forsyth} 508*37da2899SCharles.Forsyth 509*37da2899SCharles.Forsyth# return (qslice, end). 510*37da2899SCharles.Forsyth# the slice has a leading quote if the word is quoted; it does not include the terminating quote. 511*37da2899SCharles.Forsythsplitqword(s: string, start: int): ((int, int), int) 512*37da2899SCharles.Forsyth{ 513*37da2899SCharles.Forsyth for(; start < len s; start++) 514*37da2899SCharles.Forsyth if(s[start] != ' ') 515*37da2899SCharles.Forsyth break; 516*37da2899SCharles.Forsyth if(start >= len s) 517*37da2899SCharles.Forsyth return ((start, start), start); 518*37da2899SCharles.Forsyth i := start; 519*37da2899SCharles.Forsyth end := -1; 520*37da2899SCharles.Forsyth if(s[i] == '\''){ 521*37da2899SCharles.Forsyth gotq := 0; 522*37da2899SCharles.Forsyth for(i++; i < len s; i++){ 523*37da2899SCharles.Forsyth if(s[i] == '\''){ 524*37da2899SCharles.Forsyth if(i + 1 >= len s || s[i + 1] != '\''){ 525*37da2899SCharles.Forsyth end = i+1; 526*37da2899SCharles.Forsyth break; 527*37da2899SCharles.Forsyth } 528*37da2899SCharles.Forsyth i++; 529*37da2899SCharles.Forsyth gotq = 1; 530*37da2899SCharles.Forsyth } 531*37da2899SCharles.Forsyth } 532*37da2899SCharles.Forsyth if(!gotq && i > start+1) 533*37da2899SCharles.Forsyth start++; 534*37da2899SCharles.Forsyth if(end == -1) 535*37da2899SCharles.Forsyth end = i; 536*37da2899SCharles.Forsyth } else { 537*37da2899SCharles.Forsyth for(; i < len s; i++) 538*37da2899SCharles.Forsyth if(s[i] == ' ') 539*37da2899SCharles.Forsyth break; 540*37da2899SCharles.Forsyth end = i; 541*37da2899SCharles.Forsyth } 542*37da2899SCharles.Forsyth return ((start, i), end); 543*37da2899SCharles.Forsyth} 544*37da2899SCharles.Forsyth 545*37da2899SCharles.Forsyth# unquote a string slice as returned by sliceqword. 546*37da2899SCharles.Forsythqslice(s: string, r: (int, int)): string 547*37da2899SCharles.Forsyth{ 548*37da2899SCharles.Forsyth if(r.t0 == r.t1) 549*37da2899SCharles.Forsyth return nil; 550*37da2899SCharles.Forsyth if(s[r.t0] != '\'') 551*37da2899SCharles.Forsyth return s[r.t0:r.t1]; 552*37da2899SCharles.Forsyth t := ""; 553*37da2899SCharles.Forsyth for(i := r.t0 + 1; i < r.t1; i++){ 554*37da2899SCharles.Forsyth t[len t] = s[i]; 555*37da2899SCharles.Forsyth if(s[i] == '\'') 556*37da2899SCharles.Forsyth i++; 557*37da2899SCharles.Forsyth } 558*37da2899SCharles.Forsyth return t; 559*37da2899SCharles.Forsyth} 560*37da2899SCharles.Forsyth 561*37da2899SCharles.Forsythqword(s: string, start: int): (string, int) 562*37da2899SCharles.Forsyth{ 563*37da2899SCharles.Forsyth (w, next) := splitqword(s, start); 564*37da2899SCharles.Forsyth return (qslice(s, w), next); 565*37da2899SCharles.Forsyth} 566*37da2899SCharles.Forsyth 567*37da2899SCharles.Forsyths2r(s: string, e: int): (Rect, int) 568*37da2899SCharles.Forsyth{ 569*37da2899SCharles.Forsyth r: Rect; 570*37da2899SCharles.Forsyth w: string; 571*37da2899SCharles.Forsyth (w, e) = qword(s, e); 572*37da2899SCharles.Forsyth r.min.x = int w; 573*37da2899SCharles.Forsyth (w, e) = qword(s, e); 574*37da2899SCharles.Forsyth r.min.y = int w; 575*37da2899SCharles.Forsyth (w, e) = qword(s, e); 576*37da2899SCharles.Forsyth r.max.x = int w; 577*37da2899SCharles.Forsyth (w, e) = qword(s, e); 578*37da2899SCharles.Forsyth r.max.y = int w; 579*37da2899SCharles.Forsyth return (r, e); 580*37da2899SCharles.Forsyth} 581*37da2899SCharles.Forsyth 582*37da2899SCharles.Forsythkill(pid: int, note: string): int 583*37da2899SCharles.Forsyth{ 584*37da2899SCharles.Forsyth fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE); 585*37da2899SCharles.Forsyth if(fd == nil) # dodgy failover 586*37da2899SCharles.Forsyth fd = sys->open("/prog/"+string pid+"/ctl", Sys->OWRITE); 587*37da2899SCharles.Forsyth if(fd == nil || sys->fprint(fd, "%s", note) < 0) 588*37da2899SCharles.Forsyth return -1; 589*37da2899SCharles.Forsyth return 0; 590*37da2899SCharles.Forsyth} 591