implement Logwindow; # # Copyright © 1999 Vita Nuova Limited. All rights reserved. # include "sys.m"; sys: Sys; stderr: ref Sys->FD; include "draw.m"; draw: Draw; include "tk.m"; tk: Tk; cmd: import tk; include "tkclient.m"; tkclient: Tkclient; include "arg.m"; Logwindow: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; cfg := array[] of { "frame .bf", "checkbutton .bf.scroll -text Scroll -variable scroll -command {send cmd scroll}", ".bf.scroll select", "checkbutton .bf.popup -text {Pop up} -variable popup -command {send cmd popup}", ".bf.popup select", "pack .bf.scroll .bf.popup -side left", "frame .t", "scrollbar .t.scroll -command {.t.t yview}", "text .t.t -height 7c -yscrollcommand {.t.scroll set}", "pack .t.scroll -side left -fill y", "pack .t.t -fill both -expand 1", "pack .Wm_t -fill x", "pack .bf -anchor w", "pack .t -fill both -expand 1", "pack propagate . 0", }; eflag := 0; badmodule(p: string) { sys->fprint(stderr, "logwindow: cannot load %s: %r\n", p); raise "fail:bad module"; } init(ctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; stderr = sys->fildes(2); tkclient = load Tkclient Tkclient->PATH; if (tkclient == nil) badmodule(Tkclient->PATH); tkclient->init(); tk = load Tk Tk->PATH; if (tk == nil) badmodule(Tk->PATH); arg := load Arg Arg->PATH; if (arg == nil) badmodule(Arg->PATH); if (ctxt == nil) { sys->fprint(stderr, "logwindow: nil Draw->Context\n"); raise "fail:no draw context"; } gflag := 0; title := "Log Window"; arg->init(argv); while ((opt := arg->opt()) != 0) { case opt { 'e' => eflag = 1; 'g' => gflag = 1; * => sys->fprint(stderr, "usage: logwindow [-ge] [title]\n"); raise "fail:usage"; } } argv = arg->argv(); if (argv != nil) title = hd argv; if (!gflag) sys->pctl(Sys->NEWPGRP, nil); (top, wmchan) := tkclient->toplevel(ctxt, "", title, Tkclient->Hide|Tkclient->Resize); if (top == nil) { sys->fprint(stderr, "logwindow: couldn't make window\n"); raise "fail: no window"; } cmd(top, ". unmap"); for (c:=0; ccmd(top, cfg[c]); if ((err := tk->cmd(top, "variable lasterror")) != nil) { sys->fprint(stderr, "logwindow: tk error: %s\n", err); raise "fail: tk error"; } logwin(sys->fildes(0), top, wmchan); } scrolling := 1; popup := 1; logwin(fd: ref Sys->FD, top: ref Tk->Toplevel, wmchan: chan of string) { cmd := chan of string; tk->namechan(top, cmd, "cmd"); raised := 0; ichan := chan of int; spawn inputmon(fd, top, ichan); tkclient->onscreen(top, nil); tkclient->startinput(top, "kbd"::"ptr"::nil); tkclient->wmctl(top, "task"); for (;;) alt { s := <-top.ctxt.kbd => tk->keyboard(top, s); s := <-top.ctxt.ptr => tk->pointer(top, *s); s := <-top.ctxt.ctl or s = <-top.wreq or s = <-wmchan => case s { "task" => raised = 0; "untask" => raised = 1; } tkclient->wmctl(top, s); e := <-ichan => if (e == 0 && eflag) { tkclient->wmctl(top, "exit"); exit; } if (!raised && popup) tkclient->wmctl(top, "untask"); msg := <-cmd => case msg { "scroll" => scrolling = int tk->cmd(top, "variable scroll"); "popup" => popup = int tk->cmd(top, "variable popup"); } } } inputmon(fd: ref Sys->FD, top: ref Tk->Toplevel, ichan: chan of int) { buf := array[Sys->ATOMICIO] of byte; t := 0; while ((n := sys->read(fd, buf[t:], len buf-t)) > 0) { t += n; cl := 0; for (i := t - 1; i >= 0; i--) { (nil, cl, nil) = sys->byte2char(buf, i); if (cl > 0) break; } if (cl == 0) continue; logmsg(top, ichan, string buf[0:i+cl]); buf[0:] = buf[i+cl:t]; t -= i + cl; } if (n < 0) logmsg(top, ichan, sys->sprint("Input error: %r\n")); else logmsg(top, ichan, "Got EOF\n"); if (eflag) ichan <-= 0; } logmsg(top: ref Tk->Toplevel, ichan: chan of int, m: string) { tk->cmd(top, ".t.t insert end '"+m); if (scrolling) tk->cmd(top, ".t.t see end"); tk->cmd(top, "update"); ichan <-= 1; }