ref: b7af62b250e5dff30320a181ca9d53ab5a7c276d
dir: /appl/wm/stopwatch.b/
implement WmStopWatch;
include "sys.m";
sys: Sys;
include "draw.m";
draw: Draw;
include "tk.m";
tk: Tk;
include "tkclient.m";
tkclient: Tkclient;
include "daytime.m";
daytime: Daytime;
WmStopWatch: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
t: ref Tk->Toplevel;
cmd: chan of string;
tpid: int;
hr,
min,
sec: int;
sw_cfg := array[] of {
"frame .f",
"button .f.b1 -text Start -command {send cmd start}",
"button .f.b2 -text Stop -command {send cmd stop}",
"button .f.b3 -text Reset -command {send cmd reset}",
"pack .f.b1 .f.b2 .f.b3 -side left -fill x -expand 1",
"frame .ft",
"label .ft.d -label {0:00:00}",
"pack .ft.d -expand 1",
"frame .fs1",
"button .fs1.s -text Time1 -command {send cmd s1}",
"label .fs1.l -label {0:00:00}",
"pack .fs1.s .fs1.l -side left -expand 1",
"frame .fs2",
"button .fs2.s -text Time2 -command {send cmd s2}",
"label .fs2.l -label {0:00:00}",
"pack .fs2.s .fs2.l -side left -expand 1",
"frame .fs3",
"button .fs3.s -text Time3 -command {send cmd s3}",
"label .fs3.l -label {0:00:00}",
"pack .fs3.s .fs3.l -side left -expand 1",
"pack .Wm_t -fill x",
"pack .f .ft .fs1 .fs2 .fs3",
"pack propagate . 0",
"update",
};
init(ctxt: ref Draw->Context, nil: list of string)
{
sys = load Sys Sys->PATH;
if (ctxt == nil) {
sys->fprint(sys->fildes(2), "stopwatch: no window context\n");
raise "fail:bad context";
}
draw = load Draw Draw->PATH;
tk = load Tk Tk->PATH;
tkclient= load Tkclient Tkclient->PATH;
daytime = load Daytime Daytime->PATH;
if(draw==nil || tk==nil || tkclient==nil || daytime==nil){
sys->fprint(sys->fildes(2), "stopwatch: couldn't load modules\n");
return;
}
tkclient->init();
menubut := chan of string;
(t, menubut) = tkclient->toplevel(ctxt, "-borderwidth 2 -relief raised", "StopWatch", Tkclient->Appl);
hr = 0;
min = 0;
sec = 0;
cmd = chan of string;
tk->namechan(t, cmd, "cmd");
for (c:=0; c<len sw_cfg; c++)
tk->cmd(t, sw_cfg[c]);
tkclient->onscreen(t, nil);
tkclient->startinput(t, "kbd"::"ptr"::nil);
tpid = 0;
# keep the timerloop in a separate thread,
# so that wm events don't hold up the ticker
# i.e., titlebar click&hold would otherwise
# 'pause' the timer since the tick would not
# be processed.
pid := chan of int;
spawn timerloop(pid);
looppid := <- pid;
for(;;) alt {
s := <-t.ctxt.kbd =>
tk->keyboard(t, s);
s := <-t.ctxt.ptr =>
tk->pointer(t, *s);
s := <-t.ctxt.ctl or
s = <-t.wreq =>
tkclient->wmctl(t, s);
menu := <-menubut =>
if(menu == "exit") {
if(tpid)
kill(tpid);
kill(looppid);
return;
}
tkclient->wmctl(t, menu);
}
}
timerloop(pid: chan of int)
{
pid <- = sys->pctl(0, nil);
tick := chan of int;
s: string;
for(;;) alt {
c := <-cmd =>
if(c == "stop"){
if(tpid != 0){
kill(tpid);
tpid = 0;
}
} else if(c == "reset"){
hr = min = sec = 0;
s = sys->sprint("%d:%2.2d:%2.2d", hr, min, sec);
tk->cmd(t, ".ft.d configure -label {"+s+"};update");
} else if(c == "start"){
if(tpid == 0){
spawn timer(tick);
tpid = <- tick;
}
} else if(c == "s1" || c == "s2" || c == "s3"){
s = sys->sprint("%d:%2.2d:%2.2d", hr, min, sec);
tk->cmd(t, ".f"+c+".l configure -label {"+s+"};update");
}
<-tick =>
sec++;
if(sec>=60){
sec = 0;
min++;
if(min>=60){
min = 0;
hr++;
}
}
s = sys->sprint("%d:%2.2d:%2.2d", hr, min, sec);
tk->cmd(t, ".ft.d configure -label {"+s+"};update");
}
}
timer(c: chan of int)
{
pid := sys->pctl(0, nil);
for(;;) {
c <-= pid;
sys->sleep(1000);
}
}
kill(pid: int)
{
fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE);
if(fd != nil)
sys->fprint(fd, "kill");
}