Charles.Forsyth20060303a828770d19 years agoHistory
610 lines · 11.9 KB · Brainfuck
RawDownload
implement Wmsrv; include "sys.m";	sys: Sys;include "draw.m";	draw: Draw;	Display, Image, Point, Rect, Screen, Pointer, Context, Wmcontext: import draw;include "wmsrv.m"; zorder: ref Client;		# top of z-order list, linked by znext. ZR: con Rect((0, 0), (0, 0));Iqueue: adt {	h, t: list of int;	n: int;	put:			fn(q: self ref Iqueue, s: int);	get:			fn(q: self ref Iqueue): int;	peek:		fn(q: self ref Iqueue): int;	nonempty:	fn(q: self ref Iqueue): int;};Squeue: adt {	h, t: list of string;	n: int;	put:			fn(q: self ref Squeue, s: string);	get:			fn(q: self ref Squeue): string;	peek:		fn(q: self ref Squeue): string;	nonempty:	fn(q: self ref Squeue): int;};# Ptrqueue is the same as the other queues except it merges events# that have the same button state.Ptrqueue: adt {	last: ref Pointer;	h, t: list of ref Pointer;	put:			fn(q: self ref Ptrqueue, s: ref Pointer);	get:			fn(q: self ref Ptrqueue): ref Pointer;	peek:		fn(q: self ref Ptrqueue): ref Pointer;	nonempty:	fn(q: self ref Ptrqueue): int;	flush:		fn(q: self ref Ptrqueue);}; init(): 	(chan of (string, chan of (string, ref Wmcontext)),		chan of (ref Client, chan of string),		chan of (ref Client, array of byte, Sys->Rwrite)){	sys = load Sys Sys->PATH;	draw = load Draw Draw->PATH; 	sys->bind("#s", "/chan", Sys->MBEFORE); 	ctlio := sys->file2chan("/chan", "wmctl");	if(ctlio == nil){		sys->werrstr(sys->sprint("can't create /chan/wmctl: %r"));		return (nil, nil, nil);	} 	wmreq := chan of (string, chan of (string, ref Wmcontext));	join := chan of (ref Client, chan of string);	req := chan of (ref Client, array of byte, Sys->Rwrite);	spawn wm(ctlio, wmreq, join, req);	return (wmreq, join, req);} wm(ctlio: ref Sys->FileIO,			wmreq: chan of (string, chan of (string, ref Wmcontext)),			join: chan of (ref Client, chan of string),			req: chan of (ref Client, array of byte, Sys->Rwrite)){	clients: array of ref Client; 	for(;;)alt{	(cmd, rc) := <-wmreq =>		token := int cmd;		for(i := 0; i < len clients; i++)			if(clients[i] != nil && clients[i].token == token)				break; 		if(i == len clients){			spawn senderror(rc, "not found");			break;		}		c := clients[i];		if(c.stop != nil){			spawn senderror(rc, "already started");			break;		}		ok := chan of string;		join <-= (c, ok);		if((e := <-ok) != nil){			spawn senderror(rc, e);			break;		}		c.stop = chan of int;		spawn childminder(c, rc); 	(nil, nbytes, fid, rc) := <-ctlio.read =>		if(rc == nil)			break;		c := findfid(clients, fid);		if(c == nil){			c = ref Client(				chan of int,				chan of ref Draw->Pointer,				chan of string,				nil,				0,				nil,				nil,				nil, 				chan of (ref Point, ref Image, chan of int),				-1,				fid,				fid,			# token; XXX could be random integer + fid				newwmcontext()			);			clients = addclient(clients, c);		}		alt{		rc <-= (sys->aprint("%d", c.token), nil) => ;		* => ;		}	(nil, data, fid, wc) := <-ctlio.write =>		c := findfid(clients, fid);		if(wc != nil){			if(c == nil){				alt{				wc <-= (0, "must read first") => ;				* => ;				}				break;			}			req <-= (c, data, wc);		}else if(c != nil){			req <-= (c, nil, nil);			delclient(clients, c);		}	}} # buffer all events between a window manager and# a client, so that one recalcitrant child can't# clog the whole system.childminder(c: ref Client, rc: chan of (string, ref Wmcontext)){	wmctxt := c.wmctxt; 	dummykbd := chan of int;	dummyptr := chan of ref Pointer;	dummyimg := chan of ref Image;	dummyctl := chan of string; 	kbdq := ref Iqueue;	ptrq := ref Ptrqueue;	ctlq := ref Squeue; 	Imgnone, Imgsend, Imgsendnil1, Imgsendnil2, Imgorigin: con iota;	img, sendimg: ref Image;	imgorigin: Point;	imgstate := Imgnone; 	# send reply to client, but make sure we don't block.Reply:	for(;;) alt{	rc <-= (nil, ref *wmctxt) =>		break Reply;	<-c.stop =>		exit;	key := <-c.kbd =>		kbdq.put(key);	ptr := <-c.ptr =>		ptrq.put(ptr);	ctl := <-c.ctl =>		ctlq.put(ctl);	} 	for(;;){		outkbd := dummykbd;		key := -1;		if(kbdq.nonempty()){			key = kbdq.peek();			outkbd = wmctxt.kbd;		} 		outptr := dummyptr;		ptr: ref Pointer;		if(ptrq.nonempty()){			ptr = ptrq.peek();			outptr = wmctxt.ptr;		} 		outctl := dummyctl;		ctl: string;		if(ctlq.nonempty()){			ctl = ctlq.peek();			outctl = wmctxt.ctl;		} 		outimg := dummyimg;		case imgstate{		Imgsend =>			outimg = wmctxt.images;			sendimg = img;		Imgsendnil1 or		Imgsendnil2 or		Imgorigin =>			outimg = wmctxt.images;			sendimg = nil;		} 		alt{		outkbd <-= key =>			kbdq.get();		outptr <-= ptr =>			ptrq.get();		outctl <-= ctl =>			ctlq.get();		outimg <-= sendimg =>			case imgstate{			Imgsend =>				imgstate = Imgnone;				img = sendimg = nil;			Imgsendnil1 =>				imgstate = Imgsendnil2;			Imgsendnil2 =>				imgstate = Imgnone;			Imgorigin =>				if(img.origin(imgorigin, imgorigin) == -1){					# XXX what can we do about this? there's no way at the moment					# of getting the information about the origin failure back to the wm,					# so we end up with an inconsistent window position.					# if the window manager blocks while we got the sync from					# the client, then a client could block the whole window manager					# which is what we're trying to avoid.					# but there's no other time we could set the origin of the window,					# and not risk mucking up the window contents.					# the short answer is that running out of image space is Bad News.				}				imgstate = Imgsend;			} 		# XXX could mark the application as unresponding if any of these queues		# start growing too much.		ch := <-c.kbd =>			kbdq.put(ch);		p := <-c.ptr =>			if(p == nil)				ptrq.flush();			else				ptrq.put(p);		e := <-c.ctl =>			ctlq.put(e);		(o, i, reply) := <-c.images =>			# can't queue multiple image requests.			if(imgstate != Imgnone)				reply <-= -1;			else {				# if the origin is being set, then we first send a nil image				# to indicate that this is happening, and then the				# image itself (reorigined).				# if a nil image is being set, then we				# send nil twice.				if(o != nil){					imgorigin = *o;					imgstate = Imgorigin;					img = i;				}else if(i != nil){					img = i;					imgstate = Imgsend;				}else					imgstate = Imgsendnil1;				reply <-= 0;			}		<-c.stop =>			# XXX do we need to unblock channels, kill, etc.?			# we should perhaps drain the ctl output channel here			# if possible, exiting if it times out.			exit;		}	}} findfid(clients: array of ref Client, fid: int): ref Client{	for(i := 0; i < len clients; i++)		if(clients[i] != nil && clients[i].fid == fid)			return clients[i];	return nil;} addclient(clients: array of ref Client, c: ref Client): array of ref Client{	for(i := 0; i < len clients; i++)		if(clients[i] == nil){			clients[i] = c;			c.id = i;			return clients;		}	nc := array[len clients + 4] of ref Client;	nc[0:] = clients;	nc[len clients] = c;	c.id = len clients;	return nc;} delclient(clients: array of ref Client, c: ref Client){	clients[c.id] = nil;} senderror(rc: chan of (string, ref Wmcontext), e: string){	rc <-= (e, nil);} Client.window(c: self ref Client, tag: string): ref Window{	for (w := c.wins; w != nil; w = tl w)		if((hd w).tag == tag)			return hd w;	return nil;} Client.image(c: self ref Client, tag: string): ref Draw->Image{	w := c.window(tag);	if(w != nil)		return w.img;	return nil;} Client.setimage(c: self ref Client, tag: string, img: ref Draw->Image): int{	# if img is nil, remove window from list.	if(img == nil){		# usual case:		if(c.wins != nil && (hd c.wins).tag == tag){			c.wins = tl c.wins;			return -1;		}		nw: list of ref Window;		for (w := c.wins; w != nil; w = tl w)			if((hd w).tag != tag)				nw = hd w :: nw;		c.wins = nil;		for(; nw != nil; nw = tl nw)			c.wins = hd nw :: c.wins;		return -1;	}	for(w := c.wins; w != nil; w = tl w)		if((hd w).tag == tag)			break;	win: ref Window;	if(w != nil)		win = hd w;	else{		win = ref Window(tag, ZR, nil);		c.wins = win :: c.wins;	}	win.img = img;	win.r = img.r;			# save so clients can set logical origin	rc := chan of int;	c.images <-= (nil, img, rc);	return <-rc;} # tell a client about a window that's moved to screen coord o.Client.setorigin(c: self ref Client, tag: string, o: Draw->Point): int{	w := c.window(tag);	if(w == nil)		return -1;	img := w.img;	if(img == nil)		return -1;	rc := chan of int;	c.images <-= (ref o, w.img, rc);	if(<-rc != -1){		w.r = (o, o.add(img.r.size()));		return 0;	}	return -1;} clientimages(c: ref Client): array of ref Image{	a := array[len c.wins] of ref Draw->Image;	i := 0;	for(w := c.wins; w != nil; w = tl w)		if((hd w).img != nil)			a[i++] = (hd w).img;	return a[0:i];} Client.top(c: self ref Client){	imgs := clientimages(c);	if(len imgs > 0)		imgs[0].screen.top(imgs); 	if(zorder == c)		return; 	prev: ref Client;	for(z := zorder; z != nil; (prev, z) = (z, z.znext))		if(z == c)			break;	if(prev != nil)		prev.znext = c.znext;	c.znext = zorder;	zorder = c;} Client.bottom(c: self ref Client){	if(c.znext == nil)		return;	imgs := clientimages(c);	if(len imgs > 0)		imgs[0].screen.bottom(imgs);	prev: ref Client;	for(z := zorder; z != nil; (prev, z) = (z, z.znext))		if(z == c)			break;	if(prev != nil)		prev.znext = c.znext;	else		zorder = c.znext;	z = c.znext;	c.znext = nil;	for(; z != nil; (prev, z) = (z, z.znext))		;	if(prev != nil)		prev.znext = c;	else		zorder = c;} Client.hide(nil: self ref Client){} Client.unhide(nil: self ref Client){} Client.remove(c: self ref Client){	prev: ref Client;	for(z := zorder; z != nil; (prev, z) = (z, z.znext))		if(z == c)			break;	if(z == nil)		return;	if(prev != nil)		prev.znext = z.znext;	else if(z != nil)		zorder = zorder.znext;} find(p: Draw->Point): ref Client{	for(z := zorder; z != nil; z = z.znext)		if(z.contains(p))			return z;	return nil;} top(): ref Client{	return zorder;} Client.contains(c: self ref Client, p: Point): int{	for(w := c.wins; w != nil; w = tl w)		if((hd w).r.contains(p))			return 1;	return 0;} r2s(r: Rect): string{	return string r.min.x + " " + string r.min.y + " " +			string r.max.x + " " + string r.max.y;} newwmcontext(): ref Wmcontext{	return ref Wmcontext(		chan of int,		chan of ref Pointer,		chan of string,		nil,		chan of ref Image,		nil,		nil	);} Iqueue.put(q: self ref Iqueue, s: int)

Lines 1–500 of 610.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t