code: purgatorio

ref: d0ab3a0dd8f6355b3603d0fb04043a9ae867639b
dir: /appl/wm/drawmux/dmview.b/

View raw version
implement DMView;

include "sys.m";
include "draw.m";
include "tk.m";
include "tkclient.m";

DMView : module {
	init : fn (ctxt : ref Draw->Context, args : list of string);
};

DMPORT : con 9998;

sys : Sys;
draw : Draw;
tk : Tk;
tkclient : Tkclient;

Display, Image, Screen, Point, Rect, Chans : import draw;

display : ref Display;
screen : ref Screen;


init(ctxt : ref Draw->Context, args : list of string)
{
	sys = load Sys Sys->PATH;
	draw = load Draw Draw->PATH;
	tk = load Tk Tk->PATH;
	if (tk == nil)
		fail(sys->sprint("cannot load %s: %r", Tk->PATH), "init");

	tkclient = load Tkclient Tkclient->PATH;
	if (tkclient == nil)
		fail(sys->sprint("cannot load %s: %r", Tkclient->PATH), "init");

	args = tl args;
	if (args == nil)
		fail("usage: dmview netaddr", "usage");
	addr := hd args;
	args = tl args;

	display = ctxt.display;
	screen = ctxt.screen;

	tkclient ->init();

	(ok, nc) := sys->dial("tcp!"+addr+"!" + string DMPORT, nil);
	if (ok < 0)
		fail(sys->sprint("could not connect: %r"), "init");

	info := array [2 * 12] of byte;
	if (sys->read(nc.dfd, info, len info) != len info) {
		sys->print("protocol error\n");
		return;
	}
	dispw := int string info[0:12];
	disph := int string info[12:24];
	info = nil;

	(tktop, wmctl) := tkclient->toplevel(ctxt, "", "dmview: "+addr, Tkclient->Hide);
	if (tktop == nil)
		fail("cannot create window", "init");

	cpos := mkframe(tktop, dispw, disph);
	winr := Rect((0, 0), (dispw, disph));
	newwin := display.newimage(winr, display.image.chans, 0, Draw->White);
	# newwin := screen.newwindow(winr, Draw->Refbackup, Draw->White);
	if (newwin == nil) {
		sys->print("failed to create window: %r\n");
		return;
	}
	tk->putimage(tktop, ".c", newwin, nil);
	tk->cmd(tktop, ".c dirty");
	tk->cmd(tktop, "update");
	winr = winr.addpt(cpos);
	newwin.origin(Point(0,0), winr.min);

	pubscr := Screen.allocate(newwin, ctxt.display.black, 1);
	if (pubscr == nil) {
		sys->print("failed to create public screen: %r\n");
		return;
	}
	
	msg := array of byte sys->sprint("%11d %11s ", pubscr.id, newwin.chans.text());
	sys->write(nc.dfd, msg, len msg);
	msg = nil;

	pidc := chan of int;
	spawn srv(nc.dfd, wmctl, pidc);
	srvpid := <- pidc;

	tkclient->onscreen(tktop, nil);
	tkclient->startinput(tktop, nil);

	for (;;) {
		cmd := <- wmctl;
		case cmd {
		"srvexit" =>
sys->print("srv exit: %r\n");
			srvpid = -1;
		"exit" =>
			if (srvpid != -1)
				kill(srvpid);
			return;
		"move" =>
			newwin.origin(Point(0,0), display.image.r.max);
			tkclient->wmctl(tktop, cmd);
			x := int tk->cmd(tktop, ".c cget -actx");
			y := int tk->cmd(tktop, ".c cget -acty");
			newwin.origin(Point(0,0), Point(x, y));
		"task" =>
			newwin.origin(Point(0,0), display.image.r.max);
			tkclient->wmctl(tktop, cmd);
			x := int tk->cmd(tktop, ".c cget -actx");
			y := int tk->cmd(tktop, ".c cget -acty");
			newwin.origin(Point(0,0), Point(x, y));
		* =>
			tkclient->wmctl(tktop, cmd);
		}
	}
}

srv(fd : ref Sys->FD, done : chan of string, pidc : chan of int)
{
	pidc <-= sys->pctl(Sys->FORKNS, nil);
	sys->bind("/dev/draw", "/", Sys->MREPL);
	sys->export(fd, "/", Sys->EXPWAIT);
	done <-= "srvexit";
}

fail(msg, exc : string)
{
	sys->print("%s\n", msg);
	raise "fail:"+exc;
}

mkframe(t : ref Tk->Toplevel, w, h : int) : Point
{
	tk->cmd(t, "panel .c -width " + string w + " -height " + string h);
	tk->cmd(t, "frame .f -borderwidth 3 -relief groove");
	tk->cmd(t, "pack .c -in .f");
	tk->cmd(t, "pack .f");
	tk->cmd(t, "update");

	x := int tk->cmd(t, ".c cget -actx");
	y := int tk->cmd(t, ".c cget -acty");

	return Point(x, y);
}

kill(pid: int)
{
	if ((pctl  := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE)) != nil)
		sys->fprint(pctl, "kill");
}

tkcmd(t : ref Tk->Toplevel, c : string)
{
	s := tk->cmd(t, c);
	if (s != nil)
		sys->print("%s ERROR: %s\n", c, s);
}