xref: /inferno-os/appl/lib/wmlib.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Wmlib;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsyth#
4*37da2899SCharles.Forsyth# Copyright © 2003 Vita Nuova Holdings Limited
5*37da2899SCharles.Forsyth#
6*37da2899SCharles.Forsyth
7*37da2899SCharles.Forsyth# basic window manager functionality, used by
8*37da2899SCharles.Forsyth# tkclient and wmclient to create more usable functionality.
9*37da2899SCharles.Forsyth
10*37da2899SCharles.Forsythinclude "sys.m";
11*37da2899SCharles.Forsyth	sys: Sys;
12*37da2899SCharles.Forsythinclude "draw.m";
13*37da2899SCharles.Forsyth	draw: Draw;
14*37da2899SCharles.Forsyth	Display, Image, Screen, Rect, Point, Pointer, Wmcontext, Context: import draw;
15*37da2899SCharles.Forsythinclude "wmsrv.m";
16*37da2899SCharles.Forsythinclude "wmlib.m";
17*37da2899SCharles.Forsyth
18*37da2899SCharles.ForsythClient: adt{
19*37da2899SCharles.Forsyth	ptrpid:	int;
20*37da2899SCharles.Forsyth	kbdpid:	int;
21*37da2899SCharles.Forsyth	ctlpid:	int;
22*37da2899SCharles.Forsyth	req:		chan of (array of byte, Sys->Rwrite);
23*37da2899SCharles.Forsyth	dir:		string;
24*37da2899SCharles.Forsyth	ctlfd:		ref Sys->FD;
25*37da2899SCharles.Forsyth	winfd:	ref Sys->FD;
26*37da2899SCharles.Forsyth};
27*37da2899SCharles.Forsyth
28*37da2899SCharles.ForsythDEVWM: con "/mnt/wm";
29*37da2899SCharles.ForsythPtrsize: con 1+4*12;		# 'm' plus 4 12-byte decimal integers
30*37da2899SCharles.Forsyth
31*37da2899SCharles.Forsythkbdstarted: int;
32*37da2899SCharles.Forsythptrstarted: int;
33*37da2899SCharles.Forsythwptr: chan of Point;		# set mouse position (only if we've opened /dev/pointer directly)
34*37da2899SCharles.Forsythcswitch: chan of (string, int, chan of string);	# switch cursor images (as for wptr)
35*37da2899SCharles.Forsyth
36*37da2899SCharles.Forsythinit()
37*37da2899SCharles.Forsyth{
38*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
39*37da2899SCharles.Forsyth	draw = load Draw Draw->PATH;
40*37da2899SCharles.Forsyth}
41*37da2899SCharles.Forsyth
42*37da2899SCharles.Forsyth#	(_screen, dispi) := ctxt.display.getwindow("/dev/winname", nil, nil, 1); XXX corrupts heap... fix it!
43*37da2899SCharles.Forsyth
44*37da2899SCharles.Forsythmakedrawcontext(): ref Draw->Context
45*37da2899SCharles.Forsyth{
46*37da2899SCharles.Forsyth	display := Display.allocate(nil);
47*37da2899SCharles.Forsyth	if(display == nil){
48*37da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "wmlib: can't allocate Display: %r\n");
49*37da2899SCharles.Forsyth		raise "fail:no display";
50*37da2899SCharles.Forsyth	}
51*37da2899SCharles.Forsyth	return ref Draw->Context(display, nil, nil);
52*37da2899SCharles.Forsyth}
53*37da2899SCharles.Forsyth
54*37da2899SCharles.Forsythimportdrawcontext(devdraw, mntwm: string): (ref Draw->Context, string)
55*37da2899SCharles.Forsyth{
56*37da2899SCharles.Forsyth	if(mntwm == nil)
57*37da2899SCharles.Forsyth		mntwm = "/mnt/wm";
58*37da2899SCharles.Forsyth
59*37da2899SCharles.Forsyth	display := Display.allocate(devdraw);
60*37da2899SCharles.Forsyth	if(display == nil)
61*37da2899SCharles.Forsyth		return (nil, sys->sprint("cannot allocate display: %r"));
62*37da2899SCharles.Forsyth	(ok, nil) := sys->stat(mntwm + "/clone");
63*37da2899SCharles.Forsyth	if(ok == -1)
64*37da2899SCharles.Forsyth		return (nil, "cannot find wm namespace");
65*37da2899SCharles.Forsyth	wc := chan of (ref Draw->Context, string);
66*37da2899SCharles.Forsyth	spawn wmproxy(display, mntwm, wc);
67*37da2899SCharles.Forsyth	return <-wc;
68*37da2899SCharles.Forsyth}
69*37da2899SCharles.Forsyth
70*37da2899SCharles.Forsyth# XXX we have no way of knowing when this process should go away...
71*37da2899SCharles.Forsyth# perhaps a Draw->Context should hold a file descriptor
72*37da2899SCharles.Forsyth# so that we do.
73*37da2899SCharles.Forsythwmproxy(display: ref Display, dir: string, wc: chan of (ref Draw->Context, string))
74*37da2899SCharles.Forsyth{
75*37da2899SCharles.Forsyth	wmsrv := load Wmsrv Wmsrv->PATH;
76*37da2899SCharles.Forsyth	if(wmsrv == nil){
77*37da2899SCharles.Forsyth		wc <-= (nil, sys->sprint("cannot load %s: %r", Wmsrv->PATH));
78*37da2899SCharles.Forsyth		return;
79*37da2899SCharles.Forsyth	}
80*37da2899SCharles.Forsyth	sys->pctl(Sys->NEWFD, 1 :: 2 :: nil);
81*37da2899SCharles.Forsyth
82*37da2899SCharles.Forsyth	(wm, join, req) := wmsrv->init();
83*37da2899SCharles.Forsyth	if(wm == nil){
84*37da2899SCharles.Forsyth		wc <-= (nil, sys->sprint("%r"));
85*37da2899SCharles.Forsyth		return;
86*37da2899SCharles.Forsyth	}
87*37da2899SCharles.Forsyth	wc <-= (ref Draw->Context(display, nil, wm), nil);
88*37da2899SCharles.Forsyth
89*37da2899SCharles.Forsyth	clients: array of ref Client;
90*37da2899SCharles.Forsyth	for(;;) alt{
91*37da2899SCharles.Forsyth	(sc, rc) := <-join =>
92*37da2899SCharles.Forsyth		sync := chan of (ref Client, string);
93*37da2899SCharles.Forsyth		spawn clientproc(display, sc, dir, sync);
94*37da2899SCharles.Forsyth		(c, err) := <-sync;
95*37da2899SCharles.Forsyth		rc <-= err;
96*37da2899SCharles.Forsyth		if(c != nil){
97*37da2899SCharles.Forsyth			if(sc.id >= len clients)
98*37da2899SCharles.Forsyth				clients = (array[sc.id + 1] of ref Client)[0:] = clients;
99*37da2899SCharles.Forsyth			clients[sc.id] = c;
100*37da2899SCharles.Forsyth		}
101*37da2899SCharles.Forsyth	(sc, data, rc) := <-req =>
102*37da2899SCharles.Forsyth		clients[sc.id].req <-= (data, rc);
103*37da2899SCharles.Forsyth		if(rc == nil)
104*37da2899SCharles.Forsyth			clients[sc.id] = nil;
105*37da2899SCharles.Forsyth	}
106*37da2899SCharles.Forsyth}
107*37da2899SCharles.Forsyth
108*37da2899SCharles.Forsythzclient: Client;
109*37da2899SCharles.Forsythclientproc(display: ref Display, sc: ref Wmsrv->Client, dir: string, rc: chan of (ref Client, string))
110*37da2899SCharles.Forsyth{
111*37da2899SCharles.Forsyth	ctlfd := sys->open(dir + "/clone", Sys->ORDWR);
112*37da2899SCharles.Forsyth	if(ctlfd == nil){
113*37da2899SCharles.Forsyth		rc <-= (nil, sys->sprint("cannot open %s/clone: %r", dir));
114*37da2899SCharles.Forsyth		return;
115*37da2899SCharles.Forsyth	}
116*37da2899SCharles.Forsyth	buf := array[20] of byte;
117*37da2899SCharles.Forsyth	n := sys->read(ctlfd, buf, len buf);
118*37da2899SCharles.Forsyth	if(n <= 0){
119*37da2899SCharles.Forsyth		rc <-= (nil, "cannot read ctl id");
120*37da2899SCharles.Forsyth		return;
121*37da2899SCharles.Forsyth	}
122*37da2899SCharles.Forsyth	sys->fprint(ctlfd, "fixedorigin");
123*37da2899SCharles.Forsyth	dir += "/" + string buf[0:n];
124*37da2899SCharles.Forsyth	c := ref zclient;
125*37da2899SCharles.Forsyth	c.req = chan of (array of byte, Sys->Rwrite);
126*37da2899SCharles.Forsyth	c.dir = dir;
127*37da2899SCharles.Forsyth	c.ctlfd = ctlfd;
128*37da2899SCharles.Forsyth	if ((c.winfd = sys->open(dir + "/winname", Sys->OREAD)) == nil){
129*37da2899SCharles.Forsyth		rc <-= (nil, sys->sprint("cannot open %s/winname: %r", dir));
130*37da2899SCharles.Forsyth		return;
131*37da2899SCharles.Forsyth	}
132*37da2899SCharles.Forsyth	rc <-= (c, nil);
133*37da2899SCharles.Forsyth
134*37da2899SCharles.Forsyth	pidc := chan of int;
135*37da2899SCharles.Forsyth	spawn ctlproc(pidc, ctlfd, sc.ctl);
136*37da2899SCharles.Forsyth	c.ctlpid = <-pidc;
137*37da2899SCharles.Forsyth	for(;;) {
138*37da2899SCharles.Forsyth		(data, drc) := <-c.req;
139*37da2899SCharles.Forsyth		if(drc == nil)
140*37da2899SCharles.Forsyth			break;
141*37da2899SCharles.Forsyth		err := handlerequest(display, c, sc, data);
142*37da2899SCharles.Forsyth		n = len data;
143*37da2899SCharles.Forsyth		if(err != nil)
144*37da2899SCharles.Forsyth			n = -1;
145*37da2899SCharles.Forsyth		alt{
146*37da2899SCharles.Forsyth		drc <-= (n, err) =>;
147*37da2899SCharles.Forsyth		* =>;
148*37da2899SCharles.Forsyth		}
149*37da2899SCharles.Forsyth	}
150*37da2899SCharles.Forsyth	sc.stop <-= 1;
151*37da2899SCharles.Forsyth	kill(c.kbdpid, "kill");
152*37da2899SCharles.Forsyth	kill(c.ptrpid, "kill");
153*37da2899SCharles.Forsyth	kill(c.ctlpid, "kill");
154*37da2899SCharles.Forsyth	c.ctlfd = nil;
155*37da2899SCharles.Forsyth	c.winfd = nil;
156*37da2899SCharles.Forsyth}
157*37da2899SCharles.Forsyth
158*37da2899SCharles.Forsythhandlerequest(display: ref Display, c: ref Client, sc: ref Wmsrv->Client, data: array of byte): string
159*37da2899SCharles.Forsyth{
160*37da2899SCharles.Forsyth	req := string data;
161*37da2899SCharles.Forsyth	if(req == nil)
162*37da2899SCharles.Forsyth		return nil;
163*37da2899SCharles.Forsyth	(w, e) := qword(req, 0);
164*37da2899SCharles.Forsyth	case w {
165*37da2899SCharles.Forsyth	"start" =>
166*37da2899SCharles.Forsyth		(w, e) = qword(req, e);
167*37da2899SCharles.Forsyth		case w {
168*37da2899SCharles.Forsyth		"ptr" or
169*37da2899SCharles.Forsyth		"mouse" =>
170*37da2899SCharles.Forsyth			if(c.ptrpid == -1)
171*37da2899SCharles.Forsyth				return "already started";
172*37da2899SCharles.Forsyth			fd := sys->open(c.dir + "/pointer", Sys->OREAD);
173*37da2899SCharles.Forsyth			if(fd == nil)
174*37da2899SCharles.Forsyth				return sys->sprint("cannot open %s: %r", c.dir + "/pointer");
175*37da2899SCharles.Forsyth			sync := chan of int;
176*37da2899SCharles.Forsyth			spawn ptrproc(sync, fd, sc.ptr);
177*37da2899SCharles.Forsyth			c.ptrpid = <-sync;
178*37da2899SCharles.Forsyth			return nil;
179*37da2899SCharles.Forsyth		"kbd" =>
180*37da2899SCharles.Forsyth			if(c.kbdpid == -1)
181*37da2899SCharles.Forsyth				return "already started";
182*37da2899SCharles.Forsyth			sync := chan of (int, string);
183*37da2899SCharles.Forsyth			spawn kbdproc(sync, c.dir + "/keyboard", sc.kbd);
184*37da2899SCharles.Forsyth			(pid, err) := <-sync;
185*37da2899SCharles.Forsyth			c.kbdpid = pid;
186*37da2899SCharles.Forsyth			return err;
187*37da2899SCharles.Forsyth		}
188*37da2899SCharles.Forsyth	}
189*37da2899SCharles.Forsyth
190*37da2899SCharles.Forsyth	if(sys->write(c.ctlfd, data, len data) == -1)
191*37da2899SCharles.Forsyth		return sys->sprint("%r");
192*37da2899SCharles.Forsyth	if(req[0] == '!'){
193*37da2899SCharles.Forsyth		buf := array[100] of byte;
194*37da2899SCharles.Forsyth		n := sys->read(c.winfd, buf, len buf);
195*37da2899SCharles.Forsyth		if(n <= 0)
196*37da2899SCharles.Forsyth			return sys->sprint("read winname: %r");
197*37da2899SCharles.Forsyth		name := string buf[0:n];
198*37da2899SCharles.Forsyth		# XXX this is the dodgy bit...
199*37da2899SCharles.Forsyth		i := display.namedimage(name);
200*37da2899SCharles.Forsyth		if(i == nil)
201*37da2899SCharles.Forsyth			return sys->sprint("cannot get image %#q: %r", name);
202*37da2899SCharles.Forsyth		s := Screen.allocate(i, display.white, 0);
203*37da2899SCharles.Forsyth		i = s.newwindow(i.r, Draw->Refnone, Draw->Nofill);
204*37da2899SCharles.Forsyth		rc := chan of int;
205*37da2899SCharles.Forsyth		sc.images <-= (nil, i, rc);
206*37da2899SCharles.Forsyth		if(<-rc == -1)
207*37da2899SCharles.Forsyth			return "image request already in progress";
208*37da2899SCharles.Forsyth	}
209*37da2899SCharles.Forsyth	return nil;
210*37da2899SCharles.Forsyth}
211*37da2899SCharles.Forsyth
212*37da2899SCharles.Forsythconnect(ctxt: ref Context): ref Wmcontext
213*37da2899SCharles.Forsyth{
214*37da2899SCharles.Forsyth	# don't automatically make a new Draw->Context, 'cos the
215*37da2899SCharles.Forsyth	# client should be aware that there's no wm so multiple
216*37da2899SCharles.Forsyth	# windows won't work correctly.
217*37da2899SCharles.Forsyth	# ... unless there's an exported wm available, of course!
218*37da2899SCharles.Forsyth	if(ctxt == nil){
219*37da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "wmlib: no draw context\n");
220*37da2899SCharles.Forsyth		raise "fail:error";
221*37da2899SCharles.Forsyth	}
222*37da2899SCharles.Forsyth	if(ctxt.wm == nil){
223*37da2899SCharles.Forsyth		wm := ref Wmcontext(
224*37da2899SCharles.Forsyth			chan of int,
225*37da2899SCharles.Forsyth			chan of ref Draw->Pointer,
226*37da2899SCharles.Forsyth			chan of string,
227*37da2899SCharles.Forsyth			nil,	# unused
228*37da2899SCharles.Forsyth			chan of ref Image,
229*37da2899SCharles.Forsyth			nil,
230*37da2899SCharles.Forsyth			ctxt
231*37da2899SCharles.Forsyth		);
232*37da2899SCharles.Forsyth		return wm;
233*37da2899SCharles.Forsyth	}
234*37da2899SCharles.Forsyth	fd := sys->open("/chan/wmctl", Sys->ORDWR);
235*37da2899SCharles.Forsyth	if(fd == nil){
236*37da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "wmlib: cannot open /chan/wmctl: %r\n");
237*37da2899SCharles.Forsyth		raise "fail:error";
238*37da2899SCharles.Forsyth	}
239*37da2899SCharles.Forsyth	buf := array[32] of byte;
240*37da2899SCharles.Forsyth	n := sys->read(fd, buf, len buf);
241*37da2899SCharles.Forsyth	if(n < 0){
242*37da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "wmlib: cannot get window token: %r\n");
243*37da2899SCharles.Forsyth		raise "fail:error";
244*37da2899SCharles.Forsyth	}
245*37da2899SCharles.Forsyth	reply := chan of (string, ref Wmcontext);
246*37da2899SCharles.Forsyth	ctxt.wm <-= (string buf[0:n], reply);
247*37da2899SCharles.Forsyth	(err, wm) := <-reply;
248*37da2899SCharles.Forsyth	if(err != nil){
249*37da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "wmlib: cannot connect: %s\n", err);
250*37da2899SCharles.Forsyth		raise "fail:" + err;
251*37da2899SCharles.Forsyth	}
252*37da2899SCharles.Forsyth	wm.connfd = fd;
253*37da2899SCharles.Forsyth	wm.ctxt = ctxt;
254*37da2899SCharles.Forsyth	return wm;
255*37da2899SCharles.Forsyth}
256*37da2899SCharles.Forsyth
257*37da2899SCharles.Forsythstartinput(wm: ref Wmcontext, devs: list of string): string
258*37da2899SCharles.Forsyth{
259*37da2899SCharles.Forsyth	for(; devs != nil; devs = tl devs)
260*37da2899SCharles.Forsyth		wmctl(wm, "start " + hd devs);
261*37da2899SCharles.Forsyth	return nil;
262*37da2899SCharles.Forsyth}
263*37da2899SCharles.Forsyth
264*37da2899SCharles.Forsythreshape(wm: ref Wmcontext, name: string, r: Draw->Rect, i: ref Draw->Image, how: string): ref Draw->Image
265*37da2899SCharles.Forsyth{
266*37da2899SCharles.Forsyth	if(name == nil)
267*37da2899SCharles.Forsyth		return nil;
268*37da2899SCharles.Forsyth	(nil, ni, err) := wmctl(wm, sys->sprint("!reshape %s -1 %d %d %d %d %s", name, r.min.x, r.min.y, r.max.x, r.max.y, how));
269*37da2899SCharles.Forsyth	if(err == nil)
270*37da2899SCharles.Forsyth		return ni;
271*37da2899SCharles.Forsyth	return i;
272*37da2899SCharles.Forsyth}
273*37da2899SCharles.Forsyth
274*37da2899SCharles.Forsyth#
275*37da2899SCharles.Forsyth# wmctl implements the default window behaviour
276*37da2899SCharles.Forsyth#
277*37da2899SCharles.Forsythwmctl(wm: ref Wmcontext, request: string): (string, ref Image, string)
278*37da2899SCharles.Forsyth{
279*37da2899SCharles.Forsyth	(w, e) := qword(request, 0);
280*37da2899SCharles.Forsyth	case w {
281*37da2899SCharles.Forsyth	"exit" =>
282*37da2899SCharles.Forsyth		kill(sys->pctl(0, nil), "killgrp");
283*37da2899SCharles.Forsyth		exit;
284*37da2899SCharles.Forsyth	* =>
285*37da2899SCharles.Forsyth		if(wm.connfd != nil){
286*37da2899SCharles.Forsyth			# standard form for requests: if request starts with '!',
287*37da2899SCharles.Forsyth			# then the next word gives the tag of the window that the
288*37da2899SCharles.Forsyth			# request applies to, and a new image is provided.
289*37da2899SCharles.Forsyth			if(sys->fprint(wm.connfd, "%s", request) == -1){
290*37da2899SCharles.Forsyth				sys->fprint(sys->fildes(2), "wmlib: wm request '%s' failed\n", request);
291*37da2899SCharles.Forsyth				return (nil, nil, sys->sprint("%r"));
292*37da2899SCharles.Forsyth			}
293*37da2899SCharles.Forsyth			if(request[0] == '!'){
294*37da2899SCharles.Forsyth				i := <-wm.images;
295*37da2899SCharles.Forsyth				if(i == nil)
296*37da2899SCharles.Forsyth					i = <-wm.images;
297*37da2899SCharles.Forsyth				return (qword(request, e).t0, i, nil);
298*37da2899SCharles.Forsyth			}
299*37da2899SCharles.Forsyth			return (nil, nil, nil);
300*37da2899SCharles.Forsyth		}
301*37da2899SCharles.Forsyth		# requests we can handle ourselves, if we have to.
302*37da2899SCharles.Forsyth		case w{
303*37da2899SCharles.Forsyth		"start" =>
304*37da2899SCharles.Forsyth			(w, e) = qword(request, e);
305*37da2899SCharles.Forsyth			case w{
306*37da2899SCharles.Forsyth			"ptr" or
307*37da2899SCharles.Forsyth			"mouse" =>
308*37da2899SCharles.Forsyth				if(!ptrstarted){
309*37da2899SCharles.Forsyth					fd := sys->open("/dev/pointer", Sys->ORDWR);
310*37da2899SCharles.Forsyth					if(fd != nil)
311*37da2899SCharles.Forsyth						wptr = chan of Point;
312*37da2899SCharles.Forsyth					else
313*37da2899SCharles.Forsyth						fd = sys->open("/dev/pointer", Sys->OREAD);
314*37da2899SCharles.Forsyth					if(fd == nil)
315*37da2899SCharles.Forsyth						return (nil, nil, sys->sprint("cannot open /dev/pointer: %r"));
316*37da2899SCharles.Forsyth					cfd := sys->open("/dev/cursor", Sys->OWRITE);
317*37da2899SCharles.Forsyth					if(cfd != nil)
318*37da2899SCharles.Forsyth						cswitch = chan of (string, int, chan of string);
319*37da2899SCharles.Forsyth					spawn wptrproc(fd, cfd);
320*37da2899SCharles.Forsyth					sync := chan of int;
321*37da2899SCharles.Forsyth					spawn ptrproc(sync, fd, wm.ptr);
322*37da2899SCharles.Forsyth					<-sync;
323*37da2899SCharles.Forsyth					ptrstarted = 1;
324*37da2899SCharles.Forsyth				}
325*37da2899SCharles.Forsyth			"kbd" =>
326*37da2899SCharles.Forsyth				if(!kbdstarted){
327*37da2899SCharles.Forsyth					sync := chan of (int, string);
328*37da2899SCharles.Forsyth					spawn kbdproc(sync, "/dev/keyboard", wm.kbd);
329*37da2899SCharles.Forsyth					(nil, err) := <-sync;
330*37da2899SCharles.Forsyth					if(err != nil)
331*37da2899SCharles.Forsyth						return (nil, nil, err);
332*37da2899SCharles.Forsyth					spawn sendreq(wm.ctl, "haskbdfocus 1");
333*37da2899SCharles.Forsyth					kbdstarted = 1;
334*37da2899SCharles.Forsyth				}
335*37da2899SCharles.Forsyth			* =>
336*37da2899SCharles.Forsyth				return (nil, nil, "unknown input source");
337*37da2899SCharles.Forsyth			}
338*37da2899SCharles.Forsyth			return (nil, nil, nil);
339*37da2899SCharles.Forsyth		"ptr" =>
340*37da2899SCharles.Forsyth			if(wptr == nil)
341*37da2899SCharles.Forsyth				return (nil, nil, "cannot change mouse position");
342*37da2899SCharles.Forsyth			p: Point;
343*37da2899SCharles.Forsyth			(w, e) = qword(request, e);
344*37da2899SCharles.Forsyth			p.x = int w;
345*37da2899SCharles.Forsyth			(w, e) = qword(request, e);
346*37da2899SCharles.Forsyth			p.y = int w;
347*37da2899SCharles.Forsyth			wptr <-= p;
348*37da2899SCharles.Forsyth			return (nil, nil, nil);
349*37da2899SCharles.Forsyth		"cursor" =>
350*37da2899SCharles.Forsyth			if(cswitch == nil)
351*37da2899SCharles.Forsyth				return (nil, nil, "cannot switch cursor");
352*37da2899SCharles.Forsyth			cswitch <-= (request, e, reply := chan of string);
353*37da2899SCharles.Forsyth			return (nil, nil, <-reply);
354*37da2899SCharles.Forsyth		* =>
355*37da2899SCharles.Forsyth			return (nil, nil, "unknown wmctl request");
356*37da2899SCharles.Forsyth		}
357*37da2899SCharles.Forsyth	}
358*37da2899SCharles.Forsyth}
359*37da2899SCharles.Forsyth
360*37da2899SCharles.Forsythsendreq(c: chan of string, s: string)
361*37da2899SCharles.Forsyth{
362*37da2899SCharles.Forsyth	c <-= s;
363*37da2899SCharles.Forsyth}
364*37da2899SCharles.Forsyth
365*37da2899SCharles.Forsythctlproc(sync: chan of int, fd: ref Sys->FD, ctl: chan of string)
366*37da2899SCharles.Forsyth{
367*37da2899SCharles.Forsyth	sync <-= sys->pctl(0, nil);
368*37da2899SCharles.Forsyth	buf := array[4096] of byte;
369*37da2899SCharles.Forsyth	while((n := sys->read(fd, buf, len buf)) > 0)
370*37da2899SCharles.Forsyth		ctl <-= string buf[0:n];
371*37da2899SCharles.Forsyth}
372*37da2899SCharles.Forsyth
373*37da2899SCharles.Forsythkbdproc(sync: chan of (int, string), f: string, keys: chan of int)
374*37da2899SCharles.Forsyth{
375*37da2899SCharles.Forsyth	sys->pctl(Sys->NEWFD, nil);
376*37da2899SCharles.Forsyth	fd := sys->open(f, Sys->OREAD);
377*37da2899SCharles.Forsyth	if(fd == nil){
378*37da2899SCharles.Forsyth		sync <-= (-1, sys->sprint("cannot open /dev/keyboard: %r"));
379*37da2899SCharles.Forsyth		return;
380*37da2899SCharles.Forsyth	}
381*37da2899SCharles.Forsyth	sync <-= (sys->pctl(0, nil), nil);
382*37da2899SCharles.Forsyth	buf := array[12] of byte;
383*37da2899SCharles.Forsyth	while((n := sys->read(fd, buf, len buf)) > 0){
384*37da2899SCharles.Forsyth		s := string buf[0:n];
385*37da2899SCharles.Forsyth		for(j := 0; j < len s; j++)
386*37da2899SCharles.Forsyth			keys <-= int s[j];
387*37da2899SCharles.Forsyth	}
388*37da2899SCharles.Forsyth}
389*37da2899SCharles.Forsyth
390*37da2899SCharles.Forsythwptrproc(pfd, cfd: ref Sys->FD)
391*37da2899SCharles.Forsyth{
392*37da2899SCharles.Forsyth	if(wptr == nil && cswitch == nil)
393*37da2899SCharles.Forsyth		return;
394*37da2899SCharles.Forsyth	if(wptr == nil)
395*37da2899SCharles.Forsyth		wptr = chan of Point;
396*37da2899SCharles.Forsyth	if(cswitch == nil)
397*37da2899SCharles.Forsyth		cswitch = chan of (string, int, chan of string);
398*37da2899SCharles.Forsyth	for(;;)alt{
399*37da2899SCharles.Forsyth	p := <-wptr =>
400*37da2899SCharles.Forsyth		sys->fprint(pfd, "m%11d %11d", p.x, p.y);
401*37da2899SCharles.Forsyth	(c, start, reply) := <-cswitch =>
402*37da2899SCharles.Forsyth		buf: array of byte;
403*37da2899SCharles.Forsyth		if(start == len c){
404*37da2899SCharles.Forsyth			buf = array[0] of byte;
405*37da2899SCharles.Forsyth		}else{
406*37da2899SCharles.Forsyth			hot, size: Point;
407*37da2899SCharles.Forsyth			(w, e) := qword(c, start);
408*37da2899SCharles.Forsyth			hot.x = int w;
409*37da2899SCharles.Forsyth			(w, e) = qword(c, e);
410*37da2899SCharles.Forsyth			hot.y = int w;
411*37da2899SCharles.Forsyth			(w, e) = qword(c, e);
412*37da2899SCharles.Forsyth			size.x = int w;
413*37da2899SCharles.Forsyth			(w, e) = qword(c, e);
414*37da2899SCharles.Forsyth			size.y = int w;
415*37da2899SCharles.Forsyth			((d0, d1), nil) := splitqword(c, e);
416*37da2899SCharles.Forsyth			nb := size.x/8*size.y;
417*37da2899SCharles.Forsyth			if(d1 - d0 != nb * 2){
418*37da2899SCharles.Forsyth				reply <-= "inconsistent cursor image data";
419*37da2899SCharles.Forsyth				break;
420*37da2899SCharles.Forsyth			}
421*37da2899SCharles.Forsyth			buf = array[4*4 + nb] of byte;
422*37da2899SCharles.Forsyth			bplong(buf, 0*4, hot.x);
423*37da2899SCharles.Forsyth			bplong(buf, 1*4, hot.y);
424*37da2899SCharles.Forsyth			bplong(buf, 2*4, size.x);
425*37da2899SCharles.Forsyth			bplong(buf, 3*4, size.y);
426*37da2899SCharles.Forsyth			j := 4*4;
427*37da2899SCharles.Forsyth			for(i := d0; i < d1; i += 2)
428*37da2899SCharles.Forsyth				buf[j++] = byte ((hexc(c[i]) << 4) | hexc(c[i+1]));
429*37da2899SCharles.Forsyth		}
430*37da2899SCharles.Forsyth		if(sys->write(cfd, buf, len buf) != len buf)
431*37da2899SCharles.Forsyth			reply <-= sys->sprint("%r");
432*37da2899SCharles.Forsyth		else
433*37da2899SCharles.Forsyth			reply <-= nil;
434*37da2899SCharles.Forsyth	}
435*37da2899SCharles.Forsyth}
436*37da2899SCharles.Forsyth
437*37da2899SCharles.Forsythhexc(c: int): int
438*37da2899SCharles.Forsyth{
439*37da2899SCharles.Forsyth	if(c >= '0' && c <= '9')
440*37da2899SCharles.Forsyth		return c - '0';
441*37da2899SCharles.Forsyth	if(c >= 'a' && c <= 'f')
442*37da2899SCharles.Forsyth		return c - 'a' + 10;
443*37da2899SCharles.Forsyth	if(c >= 'A' && c <= 'F')
444*37da2899SCharles.Forsyth		return c - 'A' + 10;
445*37da2899SCharles.Forsyth	return 0;
446*37da2899SCharles.Forsyth}
447*37da2899SCharles.Forsyth
448*37da2899SCharles.Forsythbplong(d: array of byte, o: int, x: int)
449*37da2899SCharles.Forsyth{
450*37da2899SCharles.Forsyth	d[o] = byte x;
451*37da2899SCharles.Forsyth	d[o+1] = byte (x >> 8);
452*37da2899SCharles.Forsyth	d[o+2] = byte (x >> 16);
453*37da2899SCharles.Forsyth	d[o+3] = byte (x >> 24);
454*37da2899SCharles.Forsyth}
455*37da2899SCharles.Forsyth
456*37da2899SCharles.Forsythptrproc(sync: chan of int, fd: ref Sys->FD, ptr: chan of ref Draw->Pointer)
457*37da2899SCharles.Forsyth{
458*37da2899SCharles.Forsyth	sync <-= sys->pctl(0, nil);
459*37da2899SCharles.Forsyth
460*37da2899SCharles.Forsyth	b:= array[Ptrsize] of byte;
461*37da2899SCharles.Forsyth	while(sys->read(fd, b, len b) > 0){
462*37da2899SCharles.Forsyth		p := bytes2ptr(b);
463*37da2899SCharles.Forsyth		if(p != nil)
464*37da2899SCharles.Forsyth			ptr <-= p;
465*37da2899SCharles.Forsyth	}
466*37da2899SCharles.Forsyth}
467*37da2899SCharles.Forsyth
468*37da2899SCharles.Forsythbytes2ptr(b: array of byte): ref Pointer
469*37da2899SCharles.Forsyth{
470*37da2899SCharles.Forsyth	if(len b < Ptrsize || int b[0] != 'm')
471*37da2899SCharles.Forsyth		return nil;
472*37da2899SCharles.Forsyth	x := int string b[1:13];
473*37da2899SCharles.Forsyth	y := int string b[13:25];
474*37da2899SCharles.Forsyth	but := int string b[25:37];
475*37da2899SCharles.Forsyth	msec := int string b[37:49];
476*37da2899SCharles.Forsyth	return ref Pointer (but, (x, y), msec);
477*37da2899SCharles.Forsyth}
478*37da2899SCharles.Forsyth
479*37da2899SCharles.Forsythsnarfbuf: string;		# at least we get *something* when there's no wm.
480*37da2899SCharles.Forsyth
481*37da2899SCharles.Forsythsnarfget(): string
482*37da2899SCharles.Forsyth{
483*37da2899SCharles.Forsyth	fd := sys->open("/chan/snarf", sys->OREAD);
484*37da2899SCharles.Forsyth	if(fd == nil)
485*37da2899SCharles.Forsyth		return snarfbuf;
486*37da2899SCharles.Forsyth
487*37da2899SCharles.Forsyth	buf := array[8192] of byte;
488*37da2899SCharles.Forsyth	nr := 0;
489*37da2899SCharles.Forsyth	while ((n := sys->read(fd, buf[nr:], len buf - nr)) > 0) {
490*37da2899SCharles.Forsyth		nr += n;
491*37da2899SCharles.Forsyth		if (nr == len buf) {
492*37da2899SCharles.Forsyth			nbuf := array[len buf * 2] of byte;
493*37da2899SCharles.Forsyth			nbuf[0:] = buf;
494*37da2899SCharles.Forsyth			buf = nbuf;
495*37da2899SCharles.Forsyth		}
496*37da2899SCharles.Forsyth	}
497*37da2899SCharles.Forsyth	return string buf[0:nr];
498*37da2899SCharles.Forsyth}
499*37da2899SCharles.Forsyth
500*37da2899SCharles.Forsythsnarfput(buf: string)
501*37da2899SCharles.Forsyth{
502*37da2899SCharles.Forsyth	fd := sys->open("/chan/snarf", sys->OWRITE);
503*37da2899SCharles.Forsyth	if(fd != nil)
504*37da2899SCharles.Forsyth		sys->fprint(fd, "%s", buf);
505*37da2899SCharles.Forsyth	else
506*37da2899SCharles.Forsyth		snarfbuf = buf;
507*37da2899SCharles.Forsyth}
508*37da2899SCharles.Forsyth
509*37da2899SCharles.Forsyth# return (qslice, end).
510*37da2899SCharles.Forsyth# the slice has a leading quote if the word is quoted; it does not include the terminating quote.
511*37da2899SCharles.Forsythsplitqword(s: string, start: int): ((int, int), int)
512*37da2899SCharles.Forsyth{
513*37da2899SCharles.Forsyth	for(; start < len s; start++)
514*37da2899SCharles.Forsyth		if(s[start] != ' ')
515*37da2899SCharles.Forsyth			break;
516*37da2899SCharles.Forsyth	if(start >= len s)
517*37da2899SCharles.Forsyth		return ((start, start), start);
518*37da2899SCharles.Forsyth	i := start;
519*37da2899SCharles.Forsyth	end := -1;
520*37da2899SCharles.Forsyth	if(s[i] == '\''){
521*37da2899SCharles.Forsyth		gotq := 0;
522*37da2899SCharles.Forsyth		for(i++; i < len s; i++){
523*37da2899SCharles.Forsyth			if(s[i] == '\''){
524*37da2899SCharles.Forsyth				if(i + 1 >= len s || s[i + 1] != '\''){
525*37da2899SCharles.Forsyth					end = i+1;
526*37da2899SCharles.Forsyth					break;
527*37da2899SCharles.Forsyth				}
528*37da2899SCharles.Forsyth				i++;
529*37da2899SCharles.Forsyth				gotq = 1;
530*37da2899SCharles.Forsyth			}
531*37da2899SCharles.Forsyth		}
532*37da2899SCharles.Forsyth		if(!gotq && i > start+1)
533*37da2899SCharles.Forsyth			start++;
534*37da2899SCharles.Forsyth		if(end == -1)
535*37da2899SCharles.Forsyth			end = i;
536*37da2899SCharles.Forsyth	} else {
537*37da2899SCharles.Forsyth		for(; i < len s; i++)
538*37da2899SCharles.Forsyth			if(s[i] == ' ')
539*37da2899SCharles.Forsyth				break;
540*37da2899SCharles.Forsyth		end = i;
541*37da2899SCharles.Forsyth	}
542*37da2899SCharles.Forsyth	return ((start, i), end);
543*37da2899SCharles.Forsyth}
544*37da2899SCharles.Forsyth
545*37da2899SCharles.Forsyth# unquote a string slice as returned by sliceqword.
546*37da2899SCharles.Forsythqslice(s: string, r: (int, int)): string
547*37da2899SCharles.Forsyth{
548*37da2899SCharles.Forsyth	if(r.t0 == r.t1)
549*37da2899SCharles.Forsyth		return nil;
550*37da2899SCharles.Forsyth	if(s[r.t0] != '\'')
551*37da2899SCharles.Forsyth		return s[r.t0:r.t1];
552*37da2899SCharles.Forsyth	t := "";
553*37da2899SCharles.Forsyth	for(i := r.t0 + 1; i < r.t1; i++){
554*37da2899SCharles.Forsyth		t[len t] = s[i];
555*37da2899SCharles.Forsyth		if(s[i] == '\'')
556*37da2899SCharles.Forsyth			i++;
557*37da2899SCharles.Forsyth	}
558*37da2899SCharles.Forsyth	return t;
559*37da2899SCharles.Forsyth}
560*37da2899SCharles.Forsyth
561*37da2899SCharles.Forsythqword(s: string, start: int): (string, int)
562*37da2899SCharles.Forsyth{
563*37da2899SCharles.Forsyth	(w, next) := splitqword(s, start);
564*37da2899SCharles.Forsyth	return (qslice(s, w), next);
565*37da2899SCharles.Forsyth}
566*37da2899SCharles.Forsyth
567*37da2899SCharles.Forsyths2r(s: string, e: int): (Rect, int)
568*37da2899SCharles.Forsyth{
569*37da2899SCharles.Forsyth	r: Rect;
570*37da2899SCharles.Forsyth	w: string;
571*37da2899SCharles.Forsyth	(w, e) = qword(s, e);
572*37da2899SCharles.Forsyth	r.min.x = int w;
573*37da2899SCharles.Forsyth	(w, e) = qword(s, e);
574*37da2899SCharles.Forsyth	r.min.y = int w;
575*37da2899SCharles.Forsyth	(w, e) = qword(s, e);
576*37da2899SCharles.Forsyth	r.max.x = int w;
577*37da2899SCharles.Forsyth	(w, e) = qword(s, e);
578*37da2899SCharles.Forsyth	r.max.y = int w;
579*37da2899SCharles.Forsyth	return (r, e);
580*37da2899SCharles.Forsyth}
581*37da2899SCharles.Forsyth
582*37da2899SCharles.Forsythkill(pid: int, note: string): int
583*37da2899SCharles.Forsyth{
584*37da2899SCharles.Forsyth	fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE);
585*37da2899SCharles.Forsyth	if(fd == nil)		# dodgy failover
586*37da2899SCharles.Forsyth		fd = sys->open("/prog/"+string pid+"/ctl", Sys->OWRITE);
587*37da2899SCharles.Forsyth	if(fd == nil || sys->fprint(fd, "%s", note) < 0)
588*37da2899SCharles.Forsyth		return -1;
589*37da2899SCharles.Forsyth	return 0;
590*37da2899SCharles.Forsyth}
591