xref: /inferno-os/appl/grid/query.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Query;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsyth#
4*37da2899SCharles.Forsyth# Copyright © 2003 Vita Nuova Holdings Limited.  All rights reserved.
5*37da2899SCharles.Forsyth#
6*37da2899SCharles.Forsyth
7*37da2899SCharles.Forsyth
8*37da2899SCharles.Forsythinclude "sys.m";
9*37da2899SCharles.Forsyth	sys : Sys;
10*37da2899SCharles.Forsythinclude "draw.m";
11*37da2899SCharles.Forsyth	draw: Draw;
12*37da2899SCharles.Forsyth	Display, Rect, Image: import draw;
13*37da2899SCharles.Forsythinclude "tk.m";
14*37da2899SCharles.Forsyth	tk: Tk;
15*37da2899SCharles.Forsythinclude "tkclient.m";
16*37da2899SCharles.Forsyth	tkclient: Tkclient;
17*37da2899SCharles.Forsythinclude "readdir.m";
18*37da2899SCharles.Forsyth	readdir: Readdir;
19*37da2899SCharles.Forsythinclude "sh.m";
20*37da2899SCharles.Forsythinclude "workdir.m";
21*37da2899SCharles.Forsythinclude "registries.m";
22*37da2899SCharles.Forsyth	registries: Registries;
23*37da2899SCharles.Forsyth	Service: import registries;
24*37da2899SCharles.Forsythinclude "grid/pathreader.m";
25*37da2899SCharles.Forsyth	reader: PathReader;
26*37da2899SCharles.Forsythinclude "grid/browser.m";
27*37da2899SCharles.Forsyth	browser: Browser;
28*37da2899SCharles.Forsyth	Browse, File: import browser;
29*37da2899SCharles.Forsythinclude "grid/srvbrowse.m";
30*37da2899SCharles.Forsyth	srvbrowse: Srvbrowse;
31*37da2899SCharles.Forsythinclude "grid/fbrowse.m";
32*37da2899SCharles.Forsythinclude "grid/announce.m";
33*37da2899SCharles.Forsyth	announce: Announce;
34*37da2899SCharles.Forsyth
35*37da2899SCharles.Forsythsrvfilter : list of list of (string, string);
36*37da2899SCharles.Forsyth
37*37da2899SCharles.ForsythQuery : module {
38*37da2899SCharles.Forsyth	init : fn (context : ref Draw->Context, nil : list of string);
39*37da2899SCharles.Forsyth	readpath: fn (dir: File): (array of ref sys->Dir, int);
40*37da2899SCharles.Forsyth};
41*37da2899SCharles.Forsyth
42*37da2899SCharles.Forsythrealinit()
43*37da2899SCharles.Forsyth{
44*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
45*37da2899SCharles.Forsyth	if (sys == nil)
46*37da2899SCharles.Forsyth		badmod(Sys->PATH);
47*37da2899SCharles.Forsyth	readdir = load Readdir Readdir->PATH;
48*37da2899SCharles.Forsyth	if (readdir == nil)
49*37da2899SCharles.Forsyth		badmod(Readdir->PATH);
50*37da2899SCharles.Forsyth	draw = load Draw Draw->PATH;
51*37da2899SCharles.Forsyth	if (draw == nil)
52*37da2899SCharles.Forsyth		badmod(Draw->PATH);
53*37da2899SCharles.Forsyth	tk = load Tk Tk->PATH;
54*37da2899SCharles.Forsyth	if (tk == nil)
55*37da2899SCharles.Forsyth		badmod(Tk->PATH);
56*37da2899SCharles.Forsyth	tkclient = load Tkclient Tkclient->PATH;
57*37da2899SCharles.Forsyth	if (tkclient == nil)
58*37da2899SCharles.Forsyth		badmod(Tkclient->PATH);
59*37da2899SCharles.Forsyth	tkclient->init();
60*37da2899SCharles.Forsyth	workdir := load Workdir Workdir->PATH;
61*37da2899SCharles.Forsyth	if (workdir == nil)
62*37da2899SCharles.Forsyth		badmod(Workdir->PATH);
63*37da2899SCharles.Forsyth	registries = load Registries Registries->PATH;
64*37da2899SCharles.Forsyth	if (registries == nil)
65*37da2899SCharles.Forsyth		badmod(Registries->PATH);
66*37da2899SCharles.Forsyth	registries->init();
67*37da2899SCharles.Forsyth	browser = load Browser Browser->PATH;
68*37da2899SCharles.Forsyth	if (browser == nil)
69*37da2899SCharles.Forsyth		badmod(Browser->PATH);
70*37da2899SCharles.Forsyth	browser->init();
71*37da2899SCharles.Forsyth	srvbrowse = load Srvbrowse Srvbrowse->PATH;
72*37da2899SCharles.Forsyth	if (srvbrowse == nil)
73*37da2899SCharles.Forsyth		badmod(Srvbrowse->PATH);
74*37da2899SCharles.Forsyth	srvbrowse->init();
75*37da2899SCharles.Forsyth	announce = load Announce Announce->PATH;
76*37da2899SCharles.Forsyth	if (announce == nil)
77*37da2899SCharles.Forsyth		badmod(Announce->PATH);
78*37da2899SCharles.Forsyth	announce->init();
79*37da2899SCharles.Forsyth	reader = load PathReader "$self";
80*37da2899SCharles.Forsyth	if (reader == nil)
81*37da2899SCharles.Forsyth		badmod("PathReader");
82*37da2899SCharles.Forsyth}
83*37da2899SCharles.Forsyth
84*37da2899SCharles.Forsythinit(ctxt : ref Draw->Context, nil: list of string)
85*37da2899SCharles.Forsyth{
86*37da2899SCharles.Forsyth	realinit();
87*37da2899SCharles.Forsyth	spawn start(ctxt, 1);
88*37da2899SCharles.Forsyth}
89*37da2899SCharles.Forsyth
90*37da2899SCharles.Forsythstart(ctxt: ref Draw->Context, standalone: int)
91*37da2899SCharles.Forsyth{
92*37da2899SCharles.Forsyth	sys->pctl(sys->FORKNS | sys->NEWPGRP, nil);
93*37da2899SCharles.Forsyth	if (ctxt == nil)
94*37da2899SCharles.Forsyth		ctxt = tkclient->makedrawcontext();
95*37da2899SCharles.Forsyth
96*37da2899SCharles.Forsyth	if (standalone)
97*37da2899SCharles.Forsyth		sys->create("/tmp/query", sys->OREAD, sys->DMDIR | 8r777);
98*37da2899SCharles.Forsyth	root := "/";
99*37da2899SCharles.Forsyth	(top, titlebar) := tkclient->toplevel(ctxt,"","Query", tkclient->Appl);
100*37da2899SCharles.Forsyth	butchan := chan of string;
101*37da2899SCharles.Forsyth	tk->namechan(top, butchan, "butchan");
102*37da2899SCharles.Forsyth	browsechan := chan of string;
103*37da2899SCharles.Forsyth	tk->namechan(top, browsechan, "browsechan");
104*37da2899SCharles.Forsyth	br := Browse.new(top, "browsechan", "services/", "Services", 1, reader);
105*37da2899SCharles.Forsyth	br.addopened(File ("services/", nil), 1);
106*37da2899SCharles.Forsyth	srvbrowse->refreshservices(srvfilter);
107*37da2899SCharles.Forsyth	br.refresh();
108*37da2899SCharles.Forsyth
109*37da2899SCharles.Forsyth	for (ik := 0; ik < len mainscreen; ik++)
110*37da2899SCharles.Forsyth		tkcmd(top,mainscreen[ik]);
111*37da2899SCharles.Forsyth
112*37da2899SCharles.Forsyth	tkcmd(top, "pack .f -fill both -expand 1; pack propagate . 0");
113*37da2899SCharles.Forsyth	released := 1;
114*37da2899SCharles.Forsyth	title := "";
115*37da2899SCharles.Forsyth	resize(top, 400,400);
116*37da2899SCharles.Forsyth	tkclient->onscreen(top, nil);
117*37da2899SCharles.Forsyth	tkclient->startinput(top, "kbd"::"ptr"::nil);
118*37da2899SCharles.Forsyth	tkpath: string;
119*37da2899SCharles.Forsyth	main: for (;;) {
120*37da2899SCharles.Forsyth		alt {
121*37da2899SCharles.Forsyth		s := <-top.ctxt.kbd =>
122*37da2899SCharles.Forsyth			tk->keyboard(top, s);
123*37da2899SCharles.Forsyth		s := <-top.ctxt.ptr =>
124*37da2899SCharles.Forsyth			tk->pointer(top, *s);
125*37da2899SCharles.Forsyth		inp := <-browsechan =>
126*37da2899SCharles.Forsyth			(nil, lst) := sys->tokenize(inp, " \n\t");
127*37da2899SCharles.Forsyth			if (len lst > 1)
128*37da2899SCharles.Forsyth				tkpath = hd tl lst;
129*37da2899SCharles.Forsyth			selected := br.getselected(0);
130*37da2899SCharles.Forsyth			br.defaultaction(lst, nil);
131*37da2899SCharles.Forsyth			if (!File.eq(selected, br.getselected(0)))
132*37da2899SCharles.Forsyth				actionbutton(top, br.selected[0].file.path, br.selected[0].tkpath);
133*37da2899SCharles.Forsyth			tkcmd(top, "update");
134*37da2899SCharles.Forsyth		inp := <-butchan =>
135*37da2899SCharles.Forsyth			# sys->print("inp: %s\n",inp);
136*37da2899SCharles.Forsyth			(nil, lst) := sys->tokenize(inp, " \n\t");
137*37da2899SCharles.Forsyth			if (len lst > 1)
138*37da2899SCharles.Forsyth				tkpath = hd tl lst;
139*37da2899SCharles.Forsyth			case hd lst {
140*37da2899SCharles.Forsyth				"search" =>
141*37da2899SCharles.Forsyth					if (tl lst == nil)
142*37da2899SCharles.Forsyth						spawn srvbrowse->searchwin(ctxt, butchan, nil);
143*37da2899SCharles.Forsyth					else {
144*37da2899SCharles.Forsyth						if (hd tl lst == "select") {
145*37da2899SCharles.Forsyth							file := hd tl tl lst;
146*37da2899SCharles.Forsyth							for (tmp := tl tl tl lst; tl tmp != nil; tmp = tl tmp)
147*37da2899SCharles.Forsyth								file += " "+hd tmp;
148*37da2899SCharles.Forsyth							qid := hd tmp;
149*37da2899SCharles.Forsyth							br.gotoselectfile(File (file, qid));
150*37da2899SCharles.Forsyth							actionbutton(top, br.selected[0].file.path, br.selected[0].tkpath);
151*37da2899SCharles.Forsyth						}
152*37da2899SCharles.Forsyth						else if (hd tl lst == "search") {
153*37da2899SCharles.Forsyth							srvbrowse->refreshservices(srvfilter);
154*37da2899SCharles.Forsyth							br.refresh();
155*37da2899SCharles.Forsyth						}
156*37da2899SCharles.Forsyth					}
157*37da2899SCharles.Forsyth				"refresh" =>
158*37da2899SCharles.Forsyth					# ! check to see if anything is mounted first
159*37da2899SCharles.Forsyth					srvbrowse->refreshservices(srvfilter);
160*37da2899SCharles.Forsyth					br.refresh();
161*37da2899SCharles.Forsyth				"mount" =>
162*37da2899SCharles.Forsyth					file := *br.getpath(tkpath);
163*37da2899SCharles.Forsyth					(nsrv, lsrv) := sys->tokenize(file.path, "/");
164*37da2899SCharles.Forsyth					if (nsrv == 3)
165*37da2899SCharles.Forsyth						spawn mountsrv(ctxt, file, getcoords(top));
166*37da2899SCharles.Forsyth			}
167*37da2899SCharles.Forsyth			tkcmd(top, "update");
168*37da2899SCharles.Forsyth
169*37da2899SCharles.Forsyth		title = <-top.ctxt.ctl or
170*37da2899SCharles.Forsyth		title = <-top.wreq or
171*37da2899SCharles.Forsyth		title = <-titlebar =>
172*37da2899SCharles.Forsyth			if (title == "exit")
173*37da2899SCharles.Forsyth				break main;
174*37da2899SCharles.Forsyth			e := tkclient->wmctl(top, title);
175*37da2899SCharles.Forsyth			if (e == nil && title[0] == '!')
176*37da2899SCharles.Forsyth				(nil, lst) := sys->tokenize(title, " \t\n");
177*37da2899SCharles.Forsyth		}
178*37da2899SCharles.Forsyth	}
179*37da2899SCharles.Forsyth	killg(sys->pctl(0,nil));
180*37da2899SCharles.Forsyth}
181*37da2899SCharles.Forsyth
182*37da2899SCharles.Forsythresize(top: ref Tk->Toplevel, w, h: int)
183*37da2899SCharles.Forsyth{
184*37da2899SCharles.Forsyth	tkcmd(top, ". configure -x 0 -width "+string min(top.screenr.dx(), w));
185*37da2899SCharles.Forsyth	tkcmd(top, ". configure -y 0 -height "+string min(top.screenr.dy(), h));
186*37da2899SCharles.Forsyth}
187*37da2899SCharles.Forsyth
188*37da2899SCharles.Forsythmin(a, b: int): int
189*37da2899SCharles.Forsyth{
190*37da2899SCharles.Forsyth	if (a < b)
191*37da2899SCharles.Forsyth		return a;
192*37da2899SCharles.Forsyth	return b;
193*37da2899SCharles.Forsyth}
194*37da2899SCharles.Forsyth
195*37da2899SCharles.Forsythnactionbuttons := 0;
196*37da2899SCharles.Forsythactionbutton(top: ref Tk->Toplevel, path, tkpath: string)
197*37da2899SCharles.Forsyth{
198*37da2899SCharles.Forsyth	for (i := 0; i < nactionbuttons; i++) {
199*37da2899SCharles.Forsyth		tkcmd(top, "grid forget .f.ftop.baction"+string i);
200*37da2899SCharles.Forsyth		tkcmd(top, "destroy .f.ftop.baction"+string i);
201*37da2899SCharles.Forsyth	}
202*37da2899SCharles.Forsyth	if (path == nil) {
203*37da2899SCharles.Forsyth		nactionbuttons = 0;
204*37da2899SCharles.Forsyth		return;
205*37da2899SCharles.Forsyth	}
206*37da2899SCharles.Forsyth	(n, nil) := sys->tokenize(path, "/");
207*37da2899SCharles.Forsyth	buttons : list of (string, string) = nil;
208*37da2899SCharles.Forsyth	if (n == 3)
209*37da2899SCharles.Forsyth		buttons = ("Mount", "mount "+tkpath) :: buttons;
210*37da2899SCharles.Forsyth
211*37da2899SCharles.Forsyth	nactionbuttons = len buttons;
212*37da2899SCharles.Forsyth	for (i = 0; i < nactionbuttons; i++) {
213*37da2899SCharles.Forsyth		name := ".f.ftop.baction"+string i+" ";
214*37da2899SCharles.Forsyth		(text,cmd) := hd buttons;
215*37da2899SCharles.Forsyth		tkcmd(top, "button "+name+"-text {"+text+"} "+
216*37da2899SCharles.Forsyth				"-font /fonts/charon/bold.normal.font "+
217*37da2899SCharles.Forsyth				"-command {send butchan "+cmd+"}");
218*37da2899SCharles.Forsyth		tkcmd(top, "grid "+name+" -row 0 -column "+string (4+i));
219*37da2899SCharles.Forsyth		buttons = tl buttons;
220*37da2899SCharles.Forsyth	}
221*37da2899SCharles.Forsyth}
222*37da2899SCharles.Forsyth
223*37da2899SCharles.Forsythkill(pid: int)
224*37da2899SCharles.Forsyth{
225*37da2899SCharles.Forsyth	if ((fd := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE)) != nil)
226*37da2899SCharles.Forsyth		sys->fprint(fd, "kill");
227*37da2899SCharles.Forsyth}
228*37da2899SCharles.Forsyth
229*37da2899SCharles.Forsythkillg(pid: int)
230*37da2899SCharles.Forsyth{
231*37da2899SCharles.Forsyth	if ((fd := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE)) != nil)
232*37da2899SCharles.Forsyth		sys->fprint(fd, "killgrp");
233*37da2899SCharles.Forsyth}
234*37da2899SCharles.Forsyth
235*37da2899SCharles.Forsythmainscreen := array[] of {
236*37da2899SCharles.Forsyth	"frame .f",
237*37da2899SCharles.Forsyth	"frame .f.ftop",
238*37da2899SCharles.Forsyth	"variable opt command",
239*37da2899SCharles.Forsyth	"button .f.ftop.br -text {Refresh} -command {send butchan refresh} -font /fonts/charon/bold.normal.font",
240*37da2899SCharles.Forsyth	"button .f.ftop.bs -text {Search} -command {send butchan search} -font /fonts/charon/bold.normal.font",
241*37da2899SCharles.Forsyth  	"grid .f.ftop.br .f.ftop.bs -row 0",
242*37da2899SCharles.Forsyth	"grid columnconfigure .f.ftop 3 -minsize 30",
243*37da2899SCharles.Forsyth	"label .f.l -text { } -height 1 -bg red",
244*37da2899SCharles.Forsyth	"grid .f.l -row 1 -column 0 -sticky ew",
245*37da2899SCharles.Forsyth	"grid .f.ftop -row 0 -column 0 -pady 2 -sticky w",
246*37da2899SCharles.Forsyth	"grid .fbrowse -in .f -row 2 -column 0 -sticky nsew",
247*37da2899SCharles.Forsyth
248*37da2899SCharles.Forsyth	"grid columnconfigure .f 0 -weight 1",
249*37da2899SCharles.Forsyth	"grid rowconfigure .f 2 -weight 1",
250*37da2899SCharles.Forsyth
251*37da2899SCharles.Forsyth	"bind .Wm_t <Button-1> +{focus .Wm_t}",
252*37da2899SCharles.Forsyth	"bind .Wm_t.title <Button-1> +{focus .Wm_t}",
253*37da2899SCharles.Forsyth	"focus .Wm_t",
254*37da2899SCharles.Forsyth};
255*37da2899SCharles.Forsyth
256*37da2899SCharles.Forsythreadpath(dir: File): (array of ref sys->Dir, int)
257*37da2899SCharles.Forsyth{
258*37da2899SCharles.Forsyth	return srvbrowse->servicepath2Dir(dir.path, int dir.qid);
259*37da2899SCharles.Forsyth}
260*37da2899SCharles.Forsyth
261*37da2899SCharles.Forsythbadmod(path: string)
262*37da2899SCharles.Forsyth{
263*37da2899SCharles.Forsyth	sys->print("Query: failed to load %s: %r\n",path);
264*37da2899SCharles.Forsyth	exit;
265*37da2899SCharles.Forsyth}
266*37da2899SCharles.Forsyth
267*37da2899SCharles.Forsythmountscr := array[] of {
268*37da2899SCharles.Forsyth	"frame .f -borderwidth 2 -relief raised",
269*37da2899SCharles.Forsyth	"text .f.t -width 200 -height 60 -borderwidth 1 -bg white -font /fonts/charon/plain.normal.font",
270*37da2899SCharles.Forsyth	"button .f.b -text {Cancel} -command {send butchan cancel} -width 70 -font /fonts/charon/plain.normal.font",
271*37da2899SCharles.Forsyth	"grid .f.t -row 0 -column 0 -padx 10 -pady 10",
272*37da2899SCharles.Forsyth	"grid .f.b -row 1 -column 0 -sticky n",
273*37da2899SCharles.Forsyth	"grid rowconfigure .f 1 -minsize 30",
274*37da2899SCharles.Forsyth};
275*37da2899SCharles.Forsyth
276*37da2899SCharles.Forsythmountsrv(ctxt: ref Draw->Context, srvfile: File, coords: draw->Rect)
277*37da2899SCharles.Forsyth{
278*37da2899SCharles.Forsyth	(top, nil) := tkclient->toplevel(ctxt, "", nil, tkclient->Plain);
279*37da2899SCharles.Forsyth	ctlchan := chan of string;
280*37da2899SCharles.Forsyth	butchan := chan of string;
281*37da2899SCharles.Forsyth	tk->namechan(top, butchan, "butchan");
282*37da2899SCharles.Forsyth	tkcmds(top, mountscr);
283*37da2899SCharles.Forsyth	tkcmd(top, ". configure "+getcentre(top, coords)+"; pack .f; update");
284*37da2899SCharles.Forsyth	spawn mountit(ctxt, srvfile, ctlchan);
285*37da2899SCharles.Forsyth	pid := int <-ctlchan;
286*37da2899SCharles.Forsyth	tkclient->onscreen(top, "exact");
287*37da2899SCharles.Forsyth	tkclient->startinput(top, "kbd"::"ptr"::nil);
288*37da2899SCharles.Forsyth	for (;;) {
289*37da2899SCharles.Forsyth		alt {
290*37da2899SCharles.Forsyth		s := <-top.ctxt.kbd =>
291*37da2899SCharles.Forsyth			tk->keyboard(top, s);
292*37da2899SCharles.Forsyth		s := <-top.ctxt.ptr =>
293*37da2899SCharles.Forsyth			tk->pointer(top, *s);
294*37da2899SCharles.Forsyth		e := <- ctlchan =>
295*37da2899SCharles.Forsyth			if (e[0] == '!') {
296*37da2899SCharles.Forsyth				tkcmd(top, ".f.t insert end {"+e[1:]+"}");
297*37da2899SCharles.Forsyth				tkcmd(top, ".f.b configure -text {close}; update");
298*37da2899SCharles.Forsyth				pid = -1;
299*37da2899SCharles.Forsyth			}
300*37da2899SCharles.Forsyth			else if (e == "ok")
301*37da2899SCharles.Forsyth				return;
302*37da2899SCharles.Forsyth			else
303*37da2899SCharles.Forsyth				tkcmd(top, ".f.t insert end {"+e+"}; update");
304*37da2899SCharles.Forsyth		<- butchan =>
305*37da2899SCharles.Forsyth			if (pid != -1)
306*37da2899SCharles.Forsyth				kill(pid);
307*37da2899SCharles.Forsyth			return;
308*37da2899SCharles.Forsyth		}
309*37da2899SCharles.Forsyth	}
310*37da2899SCharles.Forsyth}
311*37da2899SCharles.Forsyth
312*37da2899SCharles.Forsythmountit(ctxt: ref Draw->Context, srvfile: File, ctlchan: chan of string)
313*37da2899SCharles.Forsyth{
314*37da2899SCharles.Forsyth	ctlchan <-= string sys->pctl(0,nil);
315*37da2899SCharles.Forsyth
316*37da2899SCharles.Forsyth	n := 0;
317*37da2899SCharles.Forsyth	(nil, lst) := sys->tokenize(srvfile.path, "/");
318*37da2899SCharles.Forsyth	stype := hd tl lst;
319*37da2899SCharles.Forsyth	name := hd tl tl lst;
320*37da2899SCharles.Forsyth	addr := "";
321*37da2899SCharles.Forsyth	ctlchan <-= "Connecting...\n";
322*37da2899SCharles.Forsyth	lsrv := srvbrowse->servicepath2Service(srvfile.path, srvfile.qid);
323*37da2899SCharles.Forsyth	if (len lsrv < 1) {
324*37da2899SCharles.Forsyth		ctlchan <-= "!could not find service";
325*37da2899SCharles.Forsyth		return;
326*37da2899SCharles.Forsyth	}
327*37da2899SCharles.Forsyth	srvc := hd lsrv;
328*37da2899SCharles.Forsyth
329*37da2899SCharles.Forsyth	ctlchan <-= "Mounting...\n";
330*37da2899SCharles.Forsyth
331*37da2899SCharles.Forsyth	id := 0;
332*37da2899SCharles.Forsyth	dir : string;
333*37da2899SCharles.Forsyth	for (;;) {
334*37da2899SCharles.Forsyth		dir = "/tmp/query/"+string id;
335*37da2899SCharles.Forsyth		(n2, nil) := sys->stat(dir);
336*37da2899SCharles.Forsyth		if (n2 == -1) {
337*37da2899SCharles.Forsyth			fdtmp := sys->create(dir, sys->OREAD, sys->DMDIR | 8r777);
338*37da2899SCharles.Forsyth			if (fdtmp != nil)
339*37da2899SCharles.Forsyth				break;
340*37da2899SCharles.Forsyth		}
341*37da2899SCharles.Forsyth		else {
342*37da2899SCharles.Forsyth			(dirs2, nil) := readdir->init(dir, readdir->NAME | readdir->COMPACT);
343*37da2899SCharles.Forsyth			if (len dirs2 == 0)
344*37da2899SCharles.Forsyth				break;
345*37da2899SCharles.Forsyth		}
346*37da2899SCharles.Forsyth		id++;
347*37da2899SCharles.Forsyth	}
348*37da2899SCharles.Forsyth	attached := srvc.attach(nil, nil);
349*37da2899SCharles.Forsyth	if (attached == nil) {
350*37da2899SCharles.Forsyth		ctlchan <-= sys->sprint("!could not connect: %r");
351*37da2899SCharles.Forsyth		return;
352*37da2899SCharles.Forsyth	}
353*37da2899SCharles.Forsyth	if (sys->mount(attached.fd, nil, dir, sys->MREPL, nil) != -1) {
354*37da2899SCharles.Forsyth		ctlchan <-= "ok";
355*37da2899SCharles.Forsyth		fbrowse := load FBrowse FBrowse->PATH;
356*37da2899SCharles.Forsyth		if (fbrowse == nil)
357*37da2899SCharles.Forsyth			badmod(FBrowse->PATH);
358*37da2899SCharles.Forsyth		fbrowse->init(ctxt, srvfile.path, dir, dir);
359*37da2899SCharles.Forsyth		sys->unmount(nil, dir);
360*37da2899SCharles.Forsyth		attached = nil;
361*37da2899SCharles.Forsyth	}
362*37da2899SCharles.Forsyth	else
363*37da2899SCharles.Forsyth		ctlchan <-= sys->sprint("!mount failed: %r");
364*37da2899SCharles.Forsyth}
365*37da2899SCharles.Forsyth
366*37da2899SCharles.Forsythgetcoords(top: ref Tk->Toplevel): draw->Rect
367*37da2899SCharles.Forsyth{
368*37da2899SCharles.Forsyth	h := int tkcmd(top, ". cget -height");
369*37da2899SCharles.Forsyth	w := int tkcmd(top, ". cget -width");
370*37da2899SCharles.Forsyth	x := int tkcmd(top, ". cget -actx");
371*37da2899SCharles.Forsyth	y := int tkcmd(top, ". cget -acty");
372*37da2899SCharles.Forsyth	r := draw->Rect((x,y),(x+w,y+h));
373*37da2899SCharles.Forsyth	return r;
374*37da2899SCharles.Forsyth}
375*37da2899SCharles.Forsyth
376*37da2899SCharles.Forsythgetcentre(top: ref Tk->Toplevel, winr: draw->Rect): string
377*37da2899SCharles.Forsyth{
378*37da2899SCharles.Forsyth	h := int tkcmd(top, ".f cget -height");
379*37da2899SCharles.Forsyth	w := int tkcmd(top, ".f cget -width");
380*37da2899SCharles.Forsyth	midx := winr.min.x + (winr.dx() / 2);
381*37da2899SCharles.Forsyth	midy := winr.min.y + (winr.dy() / 2);
382*37da2899SCharles.Forsyth	newx := midx - (w/2);
383*37da2899SCharles.Forsyth	newy := midy - (h/2);
384*37da2899SCharles.Forsyth	return "-x "+string newx+" -y "+string newy;
385*37da2899SCharles.Forsyth}
386*37da2899SCharles.Forsyth
387*37da2899SCharles.Forsythtkcmd(top: ref Tk->Toplevel, cmd: string): string
388*37da2899SCharles.Forsyth{
389*37da2899SCharles.Forsyth	e := tk->cmd(top, cmd);
390*37da2899SCharles.Forsyth	if (e != "" && e[0] == '!')
391*37da2899SCharles.Forsyth		sys->print("Tk error: '%s': %s\n",cmd,e);
392*37da2899SCharles.Forsyth	return e;
393*37da2899SCharles.Forsyth}
394*37da2899SCharles.Forsyth
395*37da2899SCharles.Forsythtkcmds(top: ref Tk->Toplevel, a: array of string)
396*37da2899SCharles.Forsyth{
397*37da2899SCharles.Forsyth	for (j := 0; j < len a; j++)
398*37da2899SCharles.Forsyth		tkcmd(top, a[j]);
399*37da2899SCharles.Forsyth}
400