xref: /inferno-os/appl/lib/tkclient.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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