1*37da2899SCharles.Forsythimplement Tkclient; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsyth# 4*37da2899SCharles.Forsyth# Copyright © 2003 Vita Nuova Holdings Limited 5*37da2899SCharles.Forsyth# 6*37da2899SCharles.Forsyth 7*37da2899SCharles.Forsythinclude "sys.m"; 8*37da2899SCharles.Forsyth sys: Sys; 9*37da2899SCharles.Forsythinclude "draw.m"; 10*37da2899SCharles.Forsyth draw: Draw; 11*37da2899SCharles.Forsyth Display, Image, Screen, Rect, Point, Pointer, Wmcontext, Context: import draw; 12*37da2899SCharles.Forsythinclude "tk.m"; 13*37da2899SCharles.Forsyth tk: Tk; 14*37da2899SCharles.Forsyth Toplevel: import tk; 15*37da2899SCharles.Forsythinclude "wmlib.m"; 16*37da2899SCharles.Forsyth wmlib: Wmlib; 17*37da2899SCharles.Forsyth qword, splitqword, s2r: import wmlib; 18*37da2899SCharles.Forsythinclude "titlebar.m"; 19*37da2899SCharles.Forsyth titlebar: Titlebar; 20*37da2899SCharles.Forsythinclude "tkclient.m"; 21*37da2899SCharles.Forsyth 22*37da2899SCharles.ForsythBackground: con int 16r777777FF; # should be drawn over immediately, but just in case... 23*37da2899SCharles.Forsyth 24*37da2899SCharles.Forsythinit() 25*37da2899SCharles.Forsyth{ 26*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 27*37da2899SCharles.Forsyth draw = load Draw Draw->PATH; 28*37da2899SCharles.Forsyth tk = load Tk Tk->PATH; 29*37da2899SCharles.Forsyth wmlib = load Wmlib Wmlib->PATH; 30*37da2899SCharles.Forsyth if(wmlib == nil){ 31*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "tkclient: cannot load %s: %r\n", Wmlib->PATH); 32*37da2899SCharles.Forsyth raise "fail:bad module"; 33*37da2899SCharles.Forsyth } 34*37da2899SCharles.Forsyth wmlib->init(); 35*37da2899SCharles.Forsyth titlebar = load Titlebar Titlebar->PATH; 36*37da2899SCharles.Forsyth if(titlebar == nil){ 37*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "tkclient: cannot load %s: %r\n", Titlebar->PATH); 38*37da2899SCharles.Forsyth raise "fail:bad module"; 39*37da2899SCharles.Forsyth } 40*37da2899SCharles.Forsyth titlebar->init(); 41*37da2899SCharles.Forsyth} 42*37da2899SCharles.Forsyth 43*37da2899SCharles.Forsythmakedrawcontext(): ref Draw->Context 44*37da2899SCharles.Forsyth{ 45*37da2899SCharles.Forsyth return wmlib->makedrawcontext(); 46*37da2899SCharles.Forsyth} 47*37da2899SCharles.Forsyth 48*37da2899SCharles.Forsythtoplevel(ctxt: ref Draw->Context, topconfig: string, title: string, buts: int): (ref Tk->Toplevel, chan of string) 49*37da2899SCharles.Forsyth{ 50*37da2899SCharles.Forsyth wm := wmlib->connect(ctxt); 51*37da2899SCharles.Forsyth opts := ""; 52*37da2899SCharles.Forsyth if((buts & Plain) == 0) 53*37da2899SCharles.Forsyth opts = "-borderwidth 1 -relief raised "; 54*37da2899SCharles.Forsyth top := tk->toplevel(wm.ctxt.display, opts+topconfig); 55*37da2899SCharles.Forsyth if (top == nil) { 56*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "wmlib: window creation failed (top %ux, i %ux)\n", top, top.image); 57*37da2899SCharles.Forsyth raise "fail:window creation failed"; 58*37da2899SCharles.Forsyth } 59*37da2899SCharles.Forsyth top.ctxt = wm; 60*37da2899SCharles.Forsyth readscreenrect(top); 61*37da2899SCharles.Forsyth c := titlebar->new(top, buts); 62*37da2899SCharles.Forsyth titlebar->settitle(top, title); 63*37da2899SCharles.Forsyth return (top, c); 64*37da2899SCharles.Forsyth} 65*37da2899SCharles.Forsyth 66*37da2899SCharles.Forsythreadscreenrect(top: ref Tk->Toplevel) 67*37da2899SCharles.Forsyth{ 68*37da2899SCharles.Forsyth if((fd := sys->open("/chan/wmrect", Sys->OREAD)) != nil){ 69*37da2899SCharles.Forsyth buf := array[12*4] of byte; 70*37da2899SCharles.Forsyth n := sys->read(fd, buf, len buf); 71*37da2899SCharles.Forsyth if(n > 0) 72*37da2899SCharles.Forsyth (top.screenr, nil) = s2r(string buf[0:n], 0); 73*37da2899SCharles.Forsyth } 74*37da2899SCharles.Forsyth} 75*37da2899SCharles.Forsyth 76*37da2899SCharles.Forsythonscreen(top: ref Tk->Toplevel, how: string) 77*37da2899SCharles.Forsyth{ 78*37da2899SCharles.Forsyth if(how == nil) 79*37da2899SCharles.Forsyth how = "place"; 80*37da2899SCharles.Forsyth wmctl(top, sys->sprint("!reshape . -1 %s %q", 81*37da2899SCharles.Forsyth r2s(tk->rect(top, ".", Tk->Border|Tk->Required)), how)); 82*37da2899SCharles.Forsyth} 83*37da2899SCharles.Forsyth 84*37da2899SCharles.Forsythstartinput(top: ref Tk->Toplevel, devs: list of string) 85*37da2899SCharles.Forsyth{ 86*37da2899SCharles.Forsyth for(; devs != nil; devs = tl devs) 87*37da2899SCharles.Forsyth wmctl(top, sys->sprint("start %q", hd devs)); 88*37da2899SCharles.Forsyth} 89*37da2899SCharles.Forsyth 90*37da2899SCharles.Forsythr2s(r: Rect): string 91*37da2899SCharles.Forsyth{ 92*37da2899SCharles.Forsyth return sys->sprint("%d %d %d %d", r.min.x, r.min.y, r.max.x, r.max.y); 93*37da2899SCharles.Forsyth} 94*37da2899SCharles.Forsyth 95*37da2899SCharles.Forsyth# commands originating both from tkclient and wm (via ctl) 96*37da2899SCharles.Forsythwmctl(top: ref Tk->Toplevel, req: string): string 97*37da2899SCharles.Forsyth{ 98*37da2899SCharles.Forsyth#sys->print("wmctl %s\n", req); 99*37da2899SCharles.Forsyth (c, next) := qword(req, 0); 100*37da2899SCharles.Forsyth case c { 101*37da2899SCharles.Forsyth "exit" => 102*37da2899SCharles.Forsyth sys->fprint(sys->open("/prog/" + string sys->pctl(0, nil) + "/ctl", Sys->OWRITE), "killgrp"); 103*37da2899SCharles.Forsyth exit; 104*37da2899SCharles.Forsyth # old-style requests: pass them back around in proper form. 105*37da2899SCharles.Forsyth "move" => 106*37da2899SCharles.Forsyth # move x y 107*37da2899SCharles.Forsyth titlebar->sendctl(top, "!move . -1 " + req[next:]); 108*37da2899SCharles.Forsyth "size" => 109*37da2899SCharles.Forsyth minsz := titlebar->minsize(top); 110*37da2899SCharles.Forsyth titlebar->sendctl(top, "!size . -1 " + string minsz.x + " " + string minsz.y); 111*37da2899SCharles.Forsyth "ok" or 112*37da2899SCharles.Forsyth "help" => 113*37da2899SCharles.Forsyth ; 114*37da2899SCharles.Forsyth "rect" => 115*37da2899SCharles.Forsyth r: Rect; 116*37da2899SCharles.Forsyth (c, next) = qword(req, next); 117*37da2899SCharles.Forsyth r.min.x = int c; 118*37da2899SCharles.Forsyth (c, next) = qword(req, next); 119*37da2899SCharles.Forsyth r.min.y = int c; 120*37da2899SCharles.Forsyth (c, next) = qword(req, next); 121*37da2899SCharles.Forsyth r.max.x = int c; 122*37da2899SCharles.Forsyth (c, next) = qword(req, next); 123*37da2899SCharles.Forsyth r.max.y = int c; 124*37da2899SCharles.Forsyth top.screenr = r; 125*37da2899SCharles.Forsyth "haskbdfocus" => 126*37da2899SCharles.Forsyth in := int qword(req, next).t0 != 0; 127*37da2899SCharles.Forsyth cmd(top, "focus -global " + string in); 128*37da2899SCharles.Forsyth cmd(top, "update"); 129*37da2899SCharles.Forsyth "task" => 130*37da2899SCharles.Forsyth (r, nil) := splitqword(req, next); 131*37da2899SCharles.Forsyth if(r.t0 == r.t1) 132*37da2899SCharles.Forsyth req = sys->sprint("task %q", cmd(top, ".Wm_t.title cget -text")); 133*37da2899SCharles.Forsyth if(wmreq(top, c, req, next) == nil) 134*37da2899SCharles.Forsyth cmd(top, ". unmap; update"); 135*37da2899SCharles.Forsyth "untask" => 136*37da2899SCharles.Forsyth cmd(top, ". map; update"); 137*37da2899SCharles.Forsyth return wmreq(top, c, req, next); 138*37da2899SCharles.Forsyth * => 139*37da2899SCharles.Forsyth return wmreq(top, c, req, next); 140*37da2899SCharles.Forsyth } 141*37da2899SCharles.Forsyth return nil; 142*37da2899SCharles.Forsyth} 143*37da2899SCharles.Forsyth 144*37da2899SCharles.Forsythwmreq(top: ref Tk->Toplevel, c, req: string, e: int): string 145*37da2899SCharles.Forsyth{ 146*37da2899SCharles.Forsyth err := wmreq1(top, c, req, e); 147*37da2899SCharles.Forsyth# if(err != nil) 148*37da2899SCharles.Forsyth# sys->fprint(sys->fildes(2), "tkclient: request %#q failed: %s\n", req, err); 149*37da2899SCharles.Forsyth return err; 150*37da2899SCharles.Forsyth} 151*37da2899SCharles.Forsyth 152*37da2899SCharles.Forsythwmreq1(top: ref Tk->Toplevel, c, req: string, e: int): string 153*37da2899SCharles.Forsyth{ 154*37da2899SCharles.Forsyth name, reqid: string; 155*37da2899SCharles.Forsyth if(req != nil && req[0] == '!'){ 156*37da2899SCharles.Forsyth (name, e) = qword(req, e); 157*37da2899SCharles.Forsyth (reqid, e) = qword(req, e); 158*37da2899SCharles.Forsyth if(name == nil || reqid == nil) 159*37da2899SCharles.Forsyth return "bad arg count"; 160*37da2899SCharles.Forsyth } 161*37da2899SCharles.Forsyth if(top.ctxt.connfd != nil){ 162*37da2899SCharles.Forsyth if(sys->fprint(top.ctxt.connfd, "%s", req) == -1) 163*37da2899SCharles.Forsyth return sys->sprint("%r"); 164*37da2899SCharles.Forsyth if(req[0] == '!') 165*37da2899SCharles.Forsyth recvimage(top, name, reqid); 166*37da2899SCharles.Forsyth return nil; 167*37da2899SCharles.Forsyth } 168*37da2899SCharles.Forsyth if(req[0] != '!'){ 169*37da2899SCharles.Forsyth (nil, nil, err) := wmlib->wmctl(top.ctxt, req); 170*37da2899SCharles.Forsyth return err; 171*37da2899SCharles.Forsyth } 172*37da2899SCharles.Forsyth # if there's no window manager, then we create a screen on the 173*37da2899SCharles.Forsyth # display image. there's nowhere to find the screen again except 174*37da2899SCharles.Forsyth # through the toplevel's image. that means that you can't create a 175*37da2899SCharles.Forsyth # menu without mapping a toplevel, and if you manage to unmap 176*37da2899SCharles.Forsyth # the toplevel without unmapping the menu, you'll have two 177*37da2899SCharles.Forsyth # screens on the same display image 178*37da2899SCharles.Forsyth # in the image, so 179*37da2899SCharles.Forsyth if(c != "!reshape") 180*37da2899SCharles.Forsyth return "unknown request"; 181*37da2899SCharles.Forsyth i: ref Image; 182*37da2899SCharles.Forsyth if(top.image == nil){ 183*37da2899SCharles.Forsyth if(name != ".") 184*37da2899SCharles.Forsyth return "screen not available"; 185*37da2899SCharles.Forsyth di := top.display.image; 186*37da2899SCharles.Forsyth screen := Screen.allocate(di, top.display.color(Background), 0); 187*37da2899SCharles.Forsyth di.draw(di.r, screen.fill, nil, screen.fill.r.min); 188*37da2899SCharles.Forsyth i = screen.newwindow(di.r, Draw->Refbackup, Draw->Nofill); 189*37da2899SCharles.Forsyth }else{ 190*37da2899SCharles.Forsyth if(name == ".") 191*37da2899SCharles.Forsyth i = top.image; 192*37da2899SCharles.Forsyth else 193*37da2899SCharles.Forsyth i = top.image.screen.newwindow(s2r(req, e).t0, Draw->Refbackup, Draw->Red); 194*37da2899SCharles.Forsyth } 195*37da2899SCharles.Forsyth tk->putimage(top, name+" "+reqid, i, nil); 196*37da2899SCharles.Forsyth return nil; 197*37da2899SCharles.Forsyth} 198*37da2899SCharles.Forsyth 199*37da2899SCharles.Forsythrecvimage(top: ref Tk->Toplevel, name, reqid: string) 200*37da2899SCharles.Forsyth{ 201*37da2899SCharles.Forsyth i := <-top.ctxt.images; 202*37da2899SCharles.Forsyth if(i == nil){ 203*37da2899SCharles.Forsyth cmd(top, name + " suspend"); 204*37da2899SCharles.Forsyth i = <-top.ctxt.images; 205*37da2899SCharles.Forsyth } 206*37da2899SCharles.Forsyth tk->putimage(top, name+" "+reqid, i, nil); 207*37da2899SCharles.Forsyth} 208*37da2899SCharles.Forsyth 209*37da2899SCharles.Forsythsettitle(top: ref Tk->Toplevel, name: string): string 210*37da2899SCharles.Forsyth{ 211*37da2899SCharles.Forsyth return titlebar->settitle(top, name); 212*37da2899SCharles.Forsyth} 213*37da2899SCharles.Forsyth 214*37da2899SCharles.Forsythhandler(top: ref Tk->Toplevel, stop: chan of int) 215*37da2899SCharles.Forsyth{ 216*37da2899SCharles.Forsyth ctxt := top.ctxt; 217*37da2899SCharles.Forsyth if(stop == nil) 218*37da2899SCharles.Forsyth stop = chan of int; 219*37da2899SCharles.Forsyth for(;;)alt{ 220*37da2899SCharles.Forsyth c := <-ctxt.kbd => 221*37da2899SCharles.Forsyth tk->keyboard(top, c); 222*37da2899SCharles.Forsyth p := <-ctxt.ptr => 223*37da2899SCharles.Forsyth tk->pointer(top, *p); 224*37da2899SCharles.Forsyth c := <-ctxt.ctl or 225*37da2899SCharles.Forsyth c = <-top.wreq => 226*37da2899SCharles.Forsyth wmctl(top, c); 227*37da2899SCharles.Forsyth <-stop => 228*37da2899SCharles.Forsyth exit; 229*37da2899SCharles.Forsyth } 230*37da2899SCharles.Forsyth} 231*37da2899SCharles.Forsyth 232*37da2899SCharles.Forsythsnarfget(): string 233*37da2899SCharles.Forsyth{ 234*37da2899SCharles.Forsyth return wmlib->snarfget(); 235*37da2899SCharles.Forsyth} 236*37da2899SCharles.Forsyth 237*37da2899SCharles.Forsythsnarfput(buf: string) 238*37da2899SCharles.Forsyth{ 239*37da2899SCharles.Forsyth return wmlib->snarfput(buf); 240*37da2899SCharles.Forsyth} 241*37da2899SCharles.Forsyth 242*37da2899SCharles.Forsythcmd(top: ref Tk->Toplevel, s: string): string 243*37da2899SCharles.Forsyth{ 244*37da2899SCharles.Forsyth e := tk->cmd(top, s); 245*37da2899SCharles.Forsyth if (e != nil && e[0] == '!') 246*37da2899SCharles.Forsyth sys->fprint(sys->fildes(2), "tkclient: tk error %s on '%s'\n", e, s); 247*37da2899SCharles.Forsyth return e; 248*37da2899SCharles.Forsyth} 249*37da2899SCharles.Forsyth 250