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