xref: /inferno-os/appl/lib/wmsrv.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Wmsrv;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsythinclude "sys.m";
4*37da2899SCharles.Forsyth	sys: Sys;
5*37da2899SCharles.Forsythinclude "draw.m";
6*37da2899SCharles.Forsyth	draw: Draw;
7*37da2899SCharles.Forsyth	Display, Image, Point, Rect, Screen, Pointer, Context, Wmcontext: import draw;
8*37da2899SCharles.Forsythinclude "wmsrv.m";
9*37da2899SCharles.Forsyth
10*37da2899SCharles.Forsythzorder: ref Client;		# top of z-order list, linked by znext.
11*37da2899SCharles.Forsyth
12*37da2899SCharles.ForsythZR: con Rect((0, 0), (0, 0));
13*37da2899SCharles.ForsythIqueue: adt {
14*37da2899SCharles.Forsyth	h, t: list of int;
15*37da2899SCharles.Forsyth	n: int;
16*37da2899SCharles.Forsyth	put:			fn(q: self ref Iqueue, s: int);
17*37da2899SCharles.Forsyth	get:			fn(q: self ref Iqueue): int;
18*37da2899SCharles.Forsyth	peek:		fn(q: self ref Iqueue): int;
19*37da2899SCharles.Forsyth	nonempty:	fn(q: self ref Iqueue): int;
20*37da2899SCharles.Forsyth};
21*37da2899SCharles.ForsythSqueue: adt {
22*37da2899SCharles.Forsyth	h, t: list of string;
23*37da2899SCharles.Forsyth	n: int;
24*37da2899SCharles.Forsyth	put:			fn(q: self ref Squeue, s: string);
25*37da2899SCharles.Forsyth	get:			fn(q: self ref Squeue): string;
26*37da2899SCharles.Forsyth	peek:		fn(q: self ref Squeue): string;
27*37da2899SCharles.Forsyth	nonempty:	fn(q: self ref Squeue): int;
28*37da2899SCharles.Forsyth};
29*37da2899SCharles.Forsyth# Ptrqueue is the same as the other queues except it merges events
30*37da2899SCharles.Forsyth# that have the same button state.
31*37da2899SCharles.ForsythPtrqueue: adt {
32*37da2899SCharles.Forsyth	last: ref Pointer;
33*37da2899SCharles.Forsyth	h, t: list of ref Pointer;
34*37da2899SCharles.Forsyth	put:			fn(q: self ref Ptrqueue, s: ref Pointer);
35*37da2899SCharles.Forsyth	get:			fn(q: self ref Ptrqueue): ref Pointer;
36*37da2899SCharles.Forsyth	peek:		fn(q: self ref Ptrqueue): ref Pointer;
37*37da2899SCharles.Forsyth	nonempty:	fn(q: self ref Ptrqueue): int;
38*37da2899SCharles.Forsyth	flush:		fn(q: self ref Ptrqueue);
39*37da2899SCharles.Forsyth};
40*37da2899SCharles.Forsyth
41*37da2899SCharles.Forsythinit(): 	(chan of (string, chan of (string, ref Wmcontext)),
42*37da2899SCharles.Forsyth		chan of (ref Client, chan of string),
43*37da2899SCharles.Forsyth		chan of (ref Client, array of byte, Sys->Rwrite))
44*37da2899SCharles.Forsyth{
45*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
46*37da2899SCharles.Forsyth	draw = load Draw Draw->PATH;
47*37da2899SCharles.Forsyth
48*37da2899SCharles.Forsyth	sys->bind("#s", "/chan", Sys->MBEFORE);
49*37da2899SCharles.Forsyth
50*37da2899SCharles.Forsyth	ctlio := sys->file2chan("/chan", "wmctl");
51*37da2899SCharles.Forsyth	if(ctlio == nil){
52*37da2899SCharles.Forsyth		sys->werrstr(sys->sprint("can't create /chan/wmctl: %r"));
53*37da2899SCharles.Forsyth		return (nil, nil, nil);
54*37da2899SCharles.Forsyth	}
55*37da2899SCharles.Forsyth
56*37da2899SCharles.Forsyth	wmreq := chan of (string, chan of (string, ref Wmcontext));
57*37da2899SCharles.Forsyth	join := chan of (ref Client, chan of string);
58*37da2899SCharles.Forsyth	req := chan of (ref Client, array of byte, Sys->Rwrite);
59*37da2899SCharles.Forsyth	spawn wm(ctlio, wmreq, join, req);
60*37da2899SCharles.Forsyth	return (wmreq, join, req);
61*37da2899SCharles.Forsyth}
62*37da2899SCharles.Forsyth
63*37da2899SCharles.Forsythwm(ctlio: ref Sys->FileIO,
64*37da2899SCharles.Forsyth			wmreq: chan of (string, chan of (string, ref Wmcontext)),
65*37da2899SCharles.Forsyth			join: chan of (ref Client, chan of string),
66*37da2899SCharles.Forsyth			req: chan of (ref Client, array of byte, Sys->Rwrite))
67*37da2899SCharles.Forsyth{
68*37da2899SCharles.Forsyth	clients: array of ref Client;
69*37da2899SCharles.Forsyth
70*37da2899SCharles.Forsyth	for(;;)alt{
71*37da2899SCharles.Forsyth	(cmd, rc) := <-wmreq =>
72*37da2899SCharles.Forsyth		token := int cmd;
73*37da2899SCharles.Forsyth		for(i := 0; i < len clients; i++)
74*37da2899SCharles.Forsyth			if(clients[i] != nil && clients[i].token == token)
75*37da2899SCharles.Forsyth				break;
76*37da2899SCharles.Forsyth
77*37da2899SCharles.Forsyth		if(i == len clients){
78*37da2899SCharles.Forsyth			spawn senderror(rc, "not found");
79*37da2899SCharles.Forsyth			break;
80*37da2899SCharles.Forsyth		}
81*37da2899SCharles.Forsyth		c := clients[i];
82*37da2899SCharles.Forsyth		if(c.stop != nil){
83*37da2899SCharles.Forsyth			spawn senderror(rc, "already started");
84*37da2899SCharles.Forsyth			break;
85*37da2899SCharles.Forsyth		}
86*37da2899SCharles.Forsyth		ok := chan of string;
87*37da2899SCharles.Forsyth		join <-= (c, ok);
88*37da2899SCharles.Forsyth		if((e := <-ok) != nil){
89*37da2899SCharles.Forsyth			spawn senderror(rc, e);
90*37da2899SCharles.Forsyth			break;
91*37da2899SCharles.Forsyth		}
92*37da2899SCharles.Forsyth		c.stop = chan of int;
93*37da2899SCharles.Forsyth		spawn childminder(c, rc);
94*37da2899SCharles.Forsyth
95*37da2899SCharles.Forsyth	(nil, nbytes, fid, rc) := <-ctlio.read =>
96*37da2899SCharles.Forsyth		if(rc == nil)
97*37da2899SCharles.Forsyth			break;
98*37da2899SCharles.Forsyth		c := findfid(clients, fid);
99*37da2899SCharles.Forsyth		if(c == nil){
100*37da2899SCharles.Forsyth			c = ref Client(
101*37da2899SCharles.Forsyth				chan of int,
102*37da2899SCharles.Forsyth				chan of ref Draw->Pointer,
103*37da2899SCharles.Forsyth				chan of string,
104*37da2899SCharles.Forsyth				nil,
105*37da2899SCharles.Forsyth				0,
106*37da2899SCharles.Forsyth				nil,
107*37da2899SCharles.Forsyth				nil,
108*37da2899SCharles.Forsyth				nil,
109*37da2899SCharles.Forsyth
110*37da2899SCharles.Forsyth				chan of (ref Point, ref Image, chan of int),
111*37da2899SCharles.Forsyth				-1,
112*37da2899SCharles.Forsyth				fid,
113*37da2899SCharles.Forsyth				fid,			# token; XXX could be random integer + fid
114*37da2899SCharles.Forsyth				newwmcontext()
115*37da2899SCharles.Forsyth			);
116*37da2899SCharles.Forsyth			clients = addclient(clients, c);
117*37da2899SCharles.Forsyth		}
118*37da2899SCharles.Forsyth		alt{
119*37da2899SCharles.Forsyth		rc <-= (sys->aprint("%d", c.token), nil) => ;
120*37da2899SCharles.Forsyth		* => ;
121*37da2899SCharles.Forsyth		}
122*37da2899SCharles.Forsyth	(nil, data, fid, wc) := <-ctlio.write =>
123*37da2899SCharles.Forsyth		c := findfid(clients, fid);
124*37da2899SCharles.Forsyth		if(wc != nil){
125*37da2899SCharles.Forsyth			if(c == nil){
126*37da2899SCharles.Forsyth				alt{
127*37da2899SCharles.Forsyth				wc <-= (0, "must read first") => ;
128*37da2899SCharles.Forsyth				* => ;
129*37da2899SCharles.Forsyth				}
130*37da2899SCharles.Forsyth				break;
131*37da2899SCharles.Forsyth			}
132*37da2899SCharles.Forsyth			req <-= (c, data, wc);
133*37da2899SCharles.Forsyth		}else if(c != nil){
134*37da2899SCharles.Forsyth			req <-= (c, nil, nil);
135*37da2899SCharles.Forsyth			delclient(clients, c);
136*37da2899SCharles.Forsyth		}
137*37da2899SCharles.Forsyth	}
138*37da2899SCharles.Forsyth}
139*37da2899SCharles.Forsyth
140*37da2899SCharles.Forsyth# buffer all events between a window manager and
141*37da2899SCharles.Forsyth# a client, so that one recalcitrant child can't
142*37da2899SCharles.Forsyth# clog the whole system.
143*37da2899SCharles.Forsythchildminder(c: ref Client, rc: chan of (string, ref Wmcontext))
144*37da2899SCharles.Forsyth{
145*37da2899SCharles.Forsyth	wmctxt := c.wmctxt;
146*37da2899SCharles.Forsyth
147*37da2899SCharles.Forsyth	dummykbd := chan of int;
148*37da2899SCharles.Forsyth	dummyptr := chan of ref Pointer;
149*37da2899SCharles.Forsyth	dummyimg := chan of ref Image;
150*37da2899SCharles.Forsyth	dummyctl := chan of string;
151*37da2899SCharles.Forsyth
152*37da2899SCharles.Forsyth	kbdq := ref Iqueue;
153*37da2899SCharles.Forsyth	ptrq := ref Ptrqueue;
154*37da2899SCharles.Forsyth	ctlq := ref Squeue;
155*37da2899SCharles.Forsyth
156*37da2899SCharles.Forsyth	Imgnone, Imgsend, Imgsendnil1, Imgsendnil2, Imgorigin: con iota;
157*37da2899SCharles.Forsyth	img, sendimg: ref Image;
158*37da2899SCharles.Forsyth	imgorigin: Point;
159*37da2899SCharles.Forsyth	imgstate := Imgnone;
160*37da2899SCharles.Forsyth
161*37da2899SCharles.Forsyth	# send reply to client, but make sure we don't block.
162*37da2899SCharles.ForsythReply:
163*37da2899SCharles.Forsyth	for(;;) alt{
164*37da2899SCharles.Forsyth	rc <-= (nil, ref *wmctxt) =>
165*37da2899SCharles.Forsyth		break Reply;
166*37da2899SCharles.Forsyth	<-c.stop =>
167*37da2899SCharles.Forsyth		exit;
168*37da2899SCharles.Forsyth	key := <-c.kbd =>
169*37da2899SCharles.Forsyth		kbdq.put(key);
170*37da2899SCharles.Forsyth	ptr := <-c.ptr =>
171*37da2899SCharles.Forsyth		ptrq.put(ptr);
172*37da2899SCharles.Forsyth	ctl := <-c.ctl =>
173*37da2899SCharles.Forsyth		ctlq.put(ctl);
174*37da2899SCharles.Forsyth	}
175*37da2899SCharles.Forsyth
176*37da2899SCharles.Forsyth	for(;;){
177*37da2899SCharles.Forsyth		outkbd := dummykbd;
178*37da2899SCharles.Forsyth		key := -1;
179*37da2899SCharles.Forsyth		if(kbdq.nonempty()){
180*37da2899SCharles.Forsyth			key = kbdq.peek();
181*37da2899SCharles.Forsyth			outkbd = wmctxt.kbd;
182*37da2899SCharles.Forsyth		}
183*37da2899SCharles.Forsyth
184*37da2899SCharles.Forsyth		outptr := dummyptr;
185*37da2899SCharles.Forsyth		ptr: ref Pointer;
186*37da2899SCharles.Forsyth		if(ptrq.nonempty()){
187*37da2899SCharles.Forsyth			ptr = ptrq.peek();
188*37da2899SCharles.Forsyth			outptr = wmctxt.ptr;
189*37da2899SCharles.Forsyth		}
190*37da2899SCharles.Forsyth
191*37da2899SCharles.Forsyth		outctl := dummyctl;
192*37da2899SCharles.Forsyth		ctl: string;
193*37da2899SCharles.Forsyth		if(ctlq.nonempty()){
194*37da2899SCharles.Forsyth			ctl = ctlq.peek();
195*37da2899SCharles.Forsyth			outctl = wmctxt.ctl;
196*37da2899SCharles.Forsyth		}
197*37da2899SCharles.Forsyth
198*37da2899SCharles.Forsyth		outimg := dummyimg;
199*37da2899SCharles.Forsyth		case imgstate{
200*37da2899SCharles.Forsyth		Imgsend =>
201*37da2899SCharles.Forsyth			outimg = wmctxt.images;
202*37da2899SCharles.Forsyth			sendimg = img;
203*37da2899SCharles.Forsyth		Imgsendnil1 or
204*37da2899SCharles.Forsyth		Imgsendnil2 or
205*37da2899SCharles.Forsyth		Imgorigin =>
206*37da2899SCharles.Forsyth			outimg = wmctxt.images;
207*37da2899SCharles.Forsyth			sendimg = nil;
208*37da2899SCharles.Forsyth		}
209*37da2899SCharles.Forsyth
210*37da2899SCharles.Forsyth		alt{
211*37da2899SCharles.Forsyth		outkbd <-= key =>
212*37da2899SCharles.Forsyth			kbdq.get();
213*37da2899SCharles.Forsyth		outptr <-= ptr =>
214*37da2899SCharles.Forsyth			ptrq.get();
215*37da2899SCharles.Forsyth		outctl <-= ctl =>
216*37da2899SCharles.Forsyth			ctlq.get();
217*37da2899SCharles.Forsyth		outimg <-= sendimg =>
218*37da2899SCharles.Forsyth			case imgstate{
219*37da2899SCharles.Forsyth			Imgsend =>
220*37da2899SCharles.Forsyth				imgstate = Imgnone;
221*37da2899SCharles.Forsyth				img = sendimg = nil;
222*37da2899SCharles.Forsyth			Imgsendnil1 =>
223*37da2899SCharles.Forsyth				imgstate = Imgsendnil2;
224*37da2899SCharles.Forsyth			Imgsendnil2 =>
225*37da2899SCharles.Forsyth				imgstate = Imgnone;
226*37da2899SCharles.Forsyth			Imgorigin =>
227*37da2899SCharles.Forsyth				if(img.origin(imgorigin, imgorigin) == -1){
228*37da2899SCharles.Forsyth					# XXX what can we do about this? there's no way at the moment
229*37da2899SCharles.Forsyth					# of getting the information about the origin failure back to the wm,
230*37da2899SCharles.Forsyth					# so we end up with an inconsistent window position.
231*37da2899SCharles.Forsyth					# if the window manager blocks while we got the sync from
232*37da2899SCharles.Forsyth					# the client, then a client could block the whole window manager
233*37da2899SCharles.Forsyth					# which is what we're trying to avoid.
234*37da2899SCharles.Forsyth					# but there's no other time we could set the origin of the window,
235*37da2899SCharles.Forsyth					# and not risk mucking up the window contents.
236*37da2899SCharles.Forsyth					# the short answer is that running out of image space is Bad News.
237*37da2899SCharles.Forsyth				}
238*37da2899SCharles.Forsyth				imgstate = Imgsend;
239*37da2899SCharles.Forsyth			}
240*37da2899SCharles.Forsyth
241*37da2899SCharles.Forsyth		# XXX could mark the application as unresponding if any of these queues
242*37da2899SCharles.Forsyth		# start growing too much.
243*37da2899SCharles.Forsyth		ch := <-c.kbd =>
244*37da2899SCharles.Forsyth			kbdq.put(ch);
245*37da2899SCharles.Forsyth		p := <-c.ptr =>
246*37da2899SCharles.Forsyth			if(p == nil)
247*37da2899SCharles.Forsyth				ptrq.flush();
248*37da2899SCharles.Forsyth			else
249*37da2899SCharles.Forsyth				ptrq.put(p);
250*37da2899SCharles.Forsyth		e := <-c.ctl =>
251*37da2899SCharles.Forsyth			ctlq.put(e);
252*37da2899SCharles.Forsyth		(o, i, reply) := <-c.images =>
253*37da2899SCharles.Forsyth			# can't queue multiple image requests.
254*37da2899SCharles.Forsyth			if(imgstate != Imgnone)
255*37da2899SCharles.Forsyth				reply <-= -1;
256*37da2899SCharles.Forsyth			else {
257*37da2899SCharles.Forsyth				# if the origin is being set, then we first send a nil image
258*37da2899SCharles.Forsyth				# to indicate that this is happening, and then the
259*37da2899SCharles.Forsyth				# image itself (reorigined).
260*37da2899SCharles.Forsyth				# if a nil image is being set, then we
261*37da2899SCharles.Forsyth				# send nil twice.
262*37da2899SCharles.Forsyth				if(o != nil){
263*37da2899SCharles.Forsyth					imgorigin = *o;
264*37da2899SCharles.Forsyth					imgstate = Imgorigin;
265*37da2899SCharles.Forsyth					img = i;
266*37da2899SCharles.Forsyth				}else if(i != nil){
267*37da2899SCharles.Forsyth					img = i;
268*37da2899SCharles.Forsyth					imgstate = Imgsend;
269*37da2899SCharles.Forsyth				}else
270*37da2899SCharles.Forsyth					imgstate = Imgsendnil1;
271*37da2899SCharles.Forsyth				reply <-= 0;
272*37da2899SCharles.Forsyth			}
273*37da2899SCharles.Forsyth		<-c.stop =>
274*37da2899SCharles.Forsyth			# XXX do we need to unblock channels, kill, etc.?
275*37da2899SCharles.Forsyth			# we should perhaps drain the ctl output channel here
276*37da2899SCharles.Forsyth			# if possible, exiting if it times out.
277*37da2899SCharles.Forsyth			exit;
278*37da2899SCharles.Forsyth		}
279*37da2899SCharles.Forsyth	}
280*37da2899SCharles.Forsyth}
281*37da2899SCharles.Forsyth
282*37da2899SCharles.Forsythfindfid(clients: array of ref Client, fid: int): ref Client
283*37da2899SCharles.Forsyth{
284*37da2899SCharles.Forsyth	for(i := 0; i < len clients; i++)
285*37da2899SCharles.Forsyth		if(clients[i] != nil && clients[i].fid == fid)
286*37da2899SCharles.Forsyth			return clients[i];
287*37da2899SCharles.Forsyth	return nil;
288*37da2899SCharles.Forsyth}
289*37da2899SCharles.Forsyth
290*37da2899SCharles.Forsythaddclient(clients: array of ref Client, c: ref Client): array of ref Client
291*37da2899SCharles.Forsyth{
292*37da2899SCharles.Forsyth	for(i := 0; i < len clients; i++)
293*37da2899SCharles.Forsyth		if(clients[i] == nil){
294*37da2899SCharles.Forsyth			clients[i] = c;
295*37da2899SCharles.Forsyth			c.id = i;
296*37da2899SCharles.Forsyth			return clients;
297*37da2899SCharles.Forsyth		}
298*37da2899SCharles.Forsyth	nc := array[len clients + 4] of ref Client;
299*37da2899SCharles.Forsyth	nc[0:] = clients;
300*37da2899SCharles.Forsyth	nc[len clients] = c;
301*37da2899SCharles.Forsyth	c.id = len clients;
302*37da2899SCharles.Forsyth	return nc;
303*37da2899SCharles.Forsyth}
304*37da2899SCharles.Forsyth
305*37da2899SCharles.Forsythdelclient(clients: array of ref Client, c: ref Client)
306*37da2899SCharles.Forsyth{
307*37da2899SCharles.Forsyth	clients[c.id] = nil;
308*37da2899SCharles.Forsyth}
309*37da2899SCharles.Forsyth
310*37da2899SCharles.Forsythsenderror(rc: chan of (string, ref Wmcontext), e: string)
311*37da2899SCharles.Forsyth{
312*37da2899SCharles.Forsyth	rc <-= (e, nil);
313*37da2899SCharles.Forsyth}
314*37da2899SCharles.Forsyth
315*37da2899SCharles.ForsythClient.window(c: self ref Client, tag: string): ref Window
316*37da2899SCharles.Forsyth{
317*37da2899SCharles.Forsyth	for (w := c.wins; w != nil; w = tl w)
318*37da2899SCharles.Forsyth		if((hd w).tag == tag)
319*37da2899SCharles.Forsyth			return hd w;
320*37da2899SCharles.Forsyth	return nil;
321*37da2899SCharles.Forsyth}
322*37da2899SCharles.Forsyth
323*37da2899SCharles.ForsythClient.image(c: self ref Client, tag: string): ref Draw->Image
324*37da2899SCharles.Forsyth{
325*37da2899SCharles.Forsyth	w := c.window(tag);
326*37da2899SCharles.Forsyth	if(w != nil)
327*37da2899SCharles.Forsyth		return w.img;
328*37da2899SCharles.Forsyth	return nil;
329*37da2899SCharles.Forsyth}
330*37da2899SCharles.Forsyth
331*37da2899SCharles.ForsythClient.setimage(c: self ref Client, tag: string, img: ref Draw->Image): int
332*37da2899SCharles.Forsyth{
333*37da2899SCharles.Forsyth	# if img is nil, remove window from list.
334*37da2899SCharles.Forsyth	if(img == nil){
335*37da2899SCharles.Forsyth		# usual case:
336*37da2899SCharles.Forsyth		if(c.wins != nil && (hd c.wins).tag == tag){
337*37da2899SCharles.Forsyth			c.wins = tl c.wins;
338*37da2899SCharles.Forsyth			return -1;
339*37da2899SCharles.Forsyth		}
340*37da2899SCharles.Forsyth		nw: list of ref Window;
341*37da2899SCharles.Forsyth		for (w := c.wins; w != nil; w = tl w)
342*37da2899SCharles.Forsyth			if((hd w).tag != tag)
343*37da2899SCharles.Forsyth				nw = hd w :: nw;
344*37da2899SCharles.Forsyth		c.wins = nil;
345*37da2899SCharles.Forsyth		for(; nw != nil; nw = tl nw)
346*37da2899SCharles.Forsyth			c.wins = hd nw :: c.wins;
347*37da2899SCharles.Forsyth		return -1;
348*37da2899SCharles.Forsyth	}
349*37da2899SCharles.Forsyth	for(w := c.wins; w != nil; w = tl w)
350*37da2899SCharles.Forsyth		if((hd w).tag == tag)
351*37da2899SCharles.Forsyth			break;
352*37da2899SCharles.Forsyth	win: ref Window;
353*37da2899SCharles.Forsyth	if(w != nil)
354*37da2899SCharles.Forsyth		win = hd w;
355*37da2899SCharles.Forsyth	else{
356*37da2899SCharles.Forsyth		win = ref Window(tag, ZR, nil);
357*37da2899SCharles.Forsyth		c.wins = win :: c.wins;
358*37da2899SCharles.Forsyth	}
359*37da2899SCharles.Forsyth	win.img = img;
360*37da2899SCharles.Forsyth	win.r = img.r;			# save so clients can set logical origin
361*37da2899SCharles.Forsyth	rc := chan of int;
362*37da2899SCharles.Forsyth	c.images <-= (nil, img, rc);
363*37da2899SCharles.Forsyth	return <-rc;
364*37da2899SCharles.Forsyth}
365*37da2899SCharles.Forsyth
366*37da2899SCharles.Forsyth# tell a client about a window that's moved to screen coord o.
367*37da2899SCharles.ForsythClient.setorigin(c: self ref Client, tag: string, o: Draw->Point): int
368*37da2899SCharles.Forsyth{
369*37da2899SCharles.Forsyth	w := c.window(tag);
370*37da2899SCharles.Forsyth	if(w == nil)
371*37da2899SCharles.Forsyth		return -1;
372*37da2899SCharles.Forsyth	img := w.img;
373*37da2899SCharles.Forsyth	if(img == nil)
374*37da2899SCharles.Forsyth		return -1;
375*37da2899SCharles.Forsyth	rc := chan of int;
376*37da2899SCharles.Forsyth	c.images <-= (ref o, w.img, rc);
377*37da2899SCharles.Forsyth	if(<-rc != -1){
378*37da2899SCharles.Forsyth		w.r = (o, o.add(img.r.size()));
379*37da2899SCharles.Forsyth		return 0;
380*37da2899SCharles.Forsyth	}
381*37da2899SCharles.Forsyth	return -1;
382*37da2899SCharles.Forsyth}
383*37da2899SCharles.Forsyth
384*37da2899SCharles.Forsythclientimages(c: ref Client): array of ref Image
385*37da2899SCharles.Forsyth{
386*37da2899SCharles.Forsyth	a := array[len c.wins] of ref Draw->Image;
387*37da2899SCharles.Forsyth	i := 0;
388*37da2899SCharles.Forsyth	for(w := c.wins; w != nil; w = tl w)
389*37da2899SCharles.Forsyth		if((hd w).img != nil)
390*37da2899SCharles.Forsyth			a[i++] = (hd w).img;
391*37da2899SCharles.Forsyth	return a[0:i];
392*37da2899SCharles.Forsyth}
393*37da2899SCharles.Forsyth
394*37da2899SCharles.ForsythClient.top(c: self ref Client)
395*37da2899SCharles.Forsyth{
396*37da2899SCharles.Forsyth	imgs := clientimages(c);
397*37da2899SCharles.Forsyth	if(len imgs > 0)
398*37da2899SCharles.Forsyth		imgs[0].screen.top(imgs);
399*37da2899SCharles.Forsyth
400*37da2899SCharles.Forsyth	if(zorder == c)
401*37da2899SCharles.Forsyth		return;
402*37da2899SCharles.Forsyth
403*37da2899SCharles.Forsyth	prev: ref Client;
404*37da2899SCharles.Forsyth	for(z := zorder; z != nil; (prev, z) = (z, z.znext))
405*37da2899SCharles.Forsyth		if(z == c)
406*37da2899SCharles.Forsyth			break;
407*37da2899SCharles.Forsyth	if(prev != nil)
408*37da2899SCharles.Forsyth		prev.znext = c.znext;
409*37da2899SCharles.Forsyth	c.znext = zorder;
410*37da2899SCharles.Forsyth	zorder = c;
411*37da2899SCharles.Forsyth}
412*37da2899SCharles.Forsyth
413*37da2899SCharles.ForsythClient.bottom(c: self ref Client)
414*37da2899SCharles.Forsyth{
415*37da2899SCharles.Forsyth	if(c.znext == nil)
416*37da2899SCharles.Forsyth		return;
417*37da2899SCharles.Forsyth	imgs := clientimages(c);
418*37da2899SCharles.Forsyth	if(len imgs > 0)
419*37da2899SCharles.Forsyth		imgs[0].screen.bottom(imgs);
420*37da2899SCharles.Forsyth	prev: ref Client;
421*37da2899SCharles.Forsyth	for(z := zorder; z != nil; (prev, z) = (z, z.znext))
422*37da2899SCharles.Forsyth		if(z == c)
423*37da2899SCharles.Forsyth			break;
424*37da2899SCharles.Forsyth	if(prev != nil)
425*37da2899SCharles.Forsyth		prev.znext = c.znext;
426*37da2899SCharles.Forsyth	else
427*37da2899SCharles.Forsyth		zorder = c.znext;
428*37da2899SCharles.Forsyth	z = c.znext;
429*37da2899SCharles.Forsyth	c.znext = nil;
430*37da2899SCharles.Forsyth	for(; z != nil; (prev, z) = (z, z.znext))
431*37da2899SCharles.Forsyth		;
432*37da2899SCharles.Forsyth	if(prev != nil)
433*37da2899SCharles.Forsyth		prev.znext = c;
434*37da2899SCharles.Forsyth	else
435*37da2899SCharles.Forsyth		zorder = c;
436*37da2899SCharles.Forsyth}
437*37da2899SCharles.Forsyth
438*37da2899SCharles.ForsythClient.hide(nil: self ref Client)
439*37da2899SCharles.Forsyth{
440*37da2899SCharles.Forsyth}
441*37da2899SCharles.Forsyth
442*37da2899SCharles.ForsythClient.unhide(nil: self ref Client)
443*37da2899SCharles.Forsyth{
444*37da2899SCharles.Forsyth}
445*37da2899SCharles.Forsyth
446*37da2899SCharles.ForsythClient.remove(c: self ref Client)
447*37da2899SCharles.Forsyth{
448*37da2899SCharles.Forsyth	prev: ref Client;
449*37da2899SCharles.Forsyth	for(z := zorder; z != nil; (prev, z) = (z, z.znext))
450*37da2899SCharles.Forsyth		if(z == c)
451*37da2899SCharles.Forsyth			break;
452*37da2899SCharles.Forsyth	if(z == nil)
453*37da2899SCharles.Forsyth		return;
454*37da2899SCharles.Forsyth	if(prev != nil)
455*37da2899SCharles.Forsyth		prev.znext = z.znext;
456*37da2899SCharles.Forsyth	else if(z != nil)
457*37da2899SCharles.Forsyth		zorder = zorder.znext;
458*37da2899SCharles.Forsyth}
459*37da2899SCharles.Forsyth
460*37da2899SCharles.Forsythfind(p: Draw->Point): ref Client
461*37da2899SCharles.Forsyth{
462*37da2899SCharles.Forsyth	for(z := zorder; z != nil; z = z.znext)
463*37da2899SCharles.Forsyth		if(z.contains(p))
464*37da2899SCharles.Forsyth			return z;
465*37da2899SCharles.Forsyth	return nil;
466*37da2899SCharles.Forsyth}
467*37da2899SCharles.Forsyth
468*37da2899SCharles.Forsythtop(): ref Client
469*37da2899SCharles.Forsyth{
470*37da2899SCharles.Forsyth	return zorder;
471*37da2899SCharles.Forsyth}
472*37da2899SCharles.Forsyth
473*37da2899SCharles.ForsythClient.contains(c: self ref Client, p: Point): int
474*37da2899SCharles.Forsyth{
475*37da2899SCharles.Forsyth	for(w := c.wins; w != nil; w = tl w)
476*37da2899SCharles.Forsyth		if((hd w).r.contains(p))
477*37da2899SCharles.Forsyth			return 1;
478*37da2899SCharles.Forsyth	return 0;
479*37da2899SCharles.Forsyth}
480*37da2899SCharles.Forsyth
481*37da2899SCharles.Forsythr2s(r: Rect): string
482*37da2899SCharles.Forsyth{
483*37da2899SCharles.Forsyth	return string r.min.x + " " + string r.min.y + " " +
484*37da2899SCharles.Forsyth			string r.max.x + " " + string r.max.y;
485*37da2899SCharles.Forsyth}
486*37da2899SCharles.Forsyth
487*37da2899SCharles.Forsythnewwmcontext(): ref Wmcontext
488*37da2899SCharles.Forsyth{
489*37da2899SCharles.Forsyth	return ref Wmcontext(
490*37da2899SCharles.Forsyth		chan of int,
491*37da2899SCharles.Forsyth		chan of ref Pointer,
492*37da2899SCharles.Forsyth		chan of string,
493*37da2899SCharles.Forsyth		nil,
494*37da2899SCharles.Forsyth		chan of ref Image,
495*37da2899SCharles.Forsyth		nil,
496*37da2899SCharles.Forsyth		nil
497*37da2899SCharles.Forsyth	);
498*37da2899SCharles.Forsyth}
499*37da2899SCharles.Forsyth
500*37da2899SCharles.ForsythIqueue.put(q: self ref Iqueue, s: int)
501*37da2899SCharles.Forsyth{
502*37da2899SCharles.Forsyth	q.t = s :: q.t;
503*37da2899SCharles.Forsyth}
504*37da2899SCharles.ForsythIqueue.get(q: self ref Iqueue): int
505*37da2899SCharles.Forsyth{
506*37da2899SCharles.Forsyth	s := -1;
507*37da2899SCharles.Forsyth	if(q.h == nil){
508*37da2899SCharles.Forsyth		for(t := q.t; t != nil; t = tl t)
509*37da2899SCharles.Forsyth			q.h = hd t :: q.h;
510*37da2899SCharles.Forsyth		q.t = nil;
511*37da2899SCharles.Forsyth	}
512*37da2899SCharles.Forsyth	if(q.h != nil){
513*37da2899SCharles.Forsyth		s = hd q.h;
514*37da2899SCharles.Forsyth		q.h = tl q.h;
515*37da2899SCharles.Forsyth	}
516*37da2899SCharles.Forsyth	return s;
517*37da2899SCharles.Forsyth}
518*37da2899SCharles.ForsythIqueue.peek(q: self ref Iqueue): int
519*37da2899SCharles.Forsyth{
520*37da2899SCharles.Forsyth	s := -1;
521*37da2899SCharles.Forsyth	if (q.h == nil && q.t == nil)
522*37da2899SCharles.Forsyth		return s;
523*37da2899SCharles.Forsyth	s = q.get();
524*37da2899SCharles.Forsyth	q.h = s :: q.h;
525*37da2899SCharles.Forsyth	return s;
526*37da2899SCharles.Forsyth}
527*37da2899SCharles.ForsythIqueue.nonempty(q: self ref Iqueue): int
528*37da2899SCharles.Forsyth{
529*37da2899SCharles.Forsyth	return q.h != nil || q.t != nil;
530*37da2899SCharles.Forsyth}
531*37da2899SCharles.Forsyth
532*37da2899SCharles.Forsyth
533*37da2899SCharles.ForsythSqueue.put(q: self ref Squeue, s: string)
534*37da2899SCharles.Forsyth{
535*37da2899SCharles.Forsyth	q.t = s :: q.t;
536*37da2899SCharles.Forsyth}
537*37da2899SCharles.ForsythSqueue.get(q: self ref Squeue): string
538*37da2899SCharles.Forsyth{
539*37da2899SCharles.Forsyth	s: string;
540*37da2899SCharles.Forsyth	if(q.h == nil){
541*37da2899SCharles.Forsyth		for(t := q.t; t != nil; t = tl t)
542*37da2899SCharles.Forsyth			q.h = hd t :: q.h;
543*37da2899SCharles.Forsyth		q.t = nil;
544*37da2899SCharles.Forsyth	}
545*37da2899SCharles.Forsyth	if(q.h != nil){
546*37da2899SCharles.Forsyth		s = hd q.h;
547*37da2899SCharles.Forsyth		q.h = tl q.h;
548*37da2899SCharles.Forsyth	}
549*37da2899SCharles.Forsyth	return s;
550*37da2899SCharles.Forsyth}
551*37da2899SCharles.ForsythSqueue.peek(q: self ref Squeue): string
552*37da2899SCharles.Forsyth{
553*37da2899SCharles.Forsyth	s: string;
554*37da2899SCharles.Forsyth	if (q.h == nil && q.t == nil)
555*37da2899SCharles.Forsyth		return s;
556*37da2899SCharles.Forsyth	s = q.get();
557*37da2899SCharles.Forsyth	q.h = s :: q.h;
558*37da2899SCharles.Forsyth	return s;
559*37da2899SCharles.Forsyth}
560*37da2899SCharles.ForsythSqueue.nonempty(q: self ref Squeue): int
561*37da2899SCharles.Forsyth{
562*37da2899SCharles.Forsyth	return q.h != nil || q.t != nil;
563*37da2899SCharles.Forsyth}
564*37da2899SCharles.Forsyth
565*37da2899SCharles.ForsythPtrqueue.put(q: self ref Ptrqueue, s: ref Pointer)
566*37da2899SCharles.Forsyth{
567*37da2899SCharles.Forsyth	if(q.last != nil && s.buttons == q.last.buttons)
568*37da2899SCharles.Forsyth		*q.last = *s;
569*37da2899SCharles.Forsyth	else{
570*37da2899SCharles.Forsyth		q.t = s :: q.t;
571*37da2899SCharles.Forsyth		q.last = s;
572*37da2899SCharles.Forsyth	}
573*37da2899SCharles.Forsyth}
574*37da2899SCharles.ForsythPtrqueue.get(q: self ref Ptrqueue): ref Pointer
575*37da2899SCharles.Forsyth{
576*37da2899SCharles.Forsyth	s: ref Pointer;
577*37da2899SCharles.Forsyth	h := q.h;
578*37da2899SCharles.Forsyth	if(h == nil){
579*37da2899SCharles.Forsyth		for(t := q.t; t != nil; t = tl t)
580*37da2899SCharles.Forsyth			h = hd t :: h;
581*37da2899SCharles.Forsyth		q.t = nil;
582*37da2899SCharles.Forsyth	}
583*37da2899SCharles.Forsyth	if(h != nil){
584*37da2899SCharles.Forsyth		s = hd h;
585*37da2899SCharles.Forsyth		h = tl h;
586*37da2899SCharles.Forsyth		if(h == nil)
587*37da2899SCharles.Forsyth			q.last = nil;
588*37da2899SCharles.Forsyth	}
589*37da2899SCharles.Forsyth	q.h = h;
590*37da2899SCharles.Forsyth	return s;
591*37da2899SCharles.Forsyth}
592*37da2899SCharles.ForsythPtrqueue.peek(q: self ref Ptrqueue): ref Pointer
593*37da2899SCharles.Forsyth{
594*37da2899SCharles.Forsyth	s: ref Pointer;
595*37da2899SCharles.Forsyth	if (q.h == nil && q.t == nil)
596*37da2899SCharles.Forsyth		return s;
597*37da2899SCharles.Forsyth	t := q.last;
598*37da2899SCharles.Forsyth	s = q.get();
599*37da2899SCharles.Forsyth	q.h = s :: q.h;
600*37da2899SCharles.Forsyth	q.last = t;
601*37da2899SCharles.Forsyth	return s;
602*37da2899SCharles.Forsyth}
603*37da2899SCharles.ForsythPtrqueue.nonempty(q: self ref Ptrqueue): int
604*37da2899SCharles.Forsyth{
605*37da2899SCharles.Forsyth	return q.h != nil || q.t != nil;
606*37da2899SCharles.Forsyth}
607*37da2899SCharles.ForsythPtrqueue.flush(q: self ref Ptrqueue)
608*37da2899SCharles.Forsyth{
609*37da2899SCharles.Forsyth	q.h = q.t = nil;
610*37da2899SCharles.Forsyth}
611