1implement Logwindow; 2 3# 4# Copyright © 1999 Vita Nuova Limited. All rights reserved. 5# 6 7include "sys.m"; 8 sys: Sys; 9 stderr: ref Sys->FD; 10include "draw.m"; 11 draw: Draw; 12include "tk.m"; 13 tk: Tk; 14 cmd: import tk; 15include "tkclient.m"; 16 tkclient: Tkclient; 17include "arg.m"; 18 19Logwindow: module { 20 init: fn(ctxt: ref Draw->Context, argv: list of string); 21}; 22 23cfg := array[] of { 24 "frame .bf", 25 "checkbutton .bf.scroll -text Scroll -variable scroll -command {send cmd scroll}", 26 ".bf.scroll select", 27 "checkbutton .bf.popup -text {Pop up} -variable popup -command {send cmd popup}", 28 ".bf.popup select", 29 "pack .bf.scroll .bf.popup -side left", 30 "frame .t", 31 "scrollbar .t.scroll -command {.t.t yview}", 32 "text .t.t -height 7c -yscrollcommand {.t.scroll set}", 33 "pack .t.scroll -side left -fill y", 34 "pack .t.t -fill both -expand 1", 35 "pack .Wm_t -fill x", 36 "pack .bf -anchor w", 37 "pack .t -fill both -expand 1", 38 "pack propagate . 0", 39}; 40 41eflag := 0; 42 43badmodule(p: string) 44{ 45 sys->fprint(stderr, "logwindow: cannot load %s: %r\n", p); 46 raise "fail:bad module"; 47} 48 49init(ctxt: ref Draw->Context, argv: list of string) 50{ 51 sys = load Sys Sys->PATH; 52 stderr = sys->fildes(2); 53 54 tkclient = load Tkclient Tkclient->PATH; 55 if (tkclient == nil) 56 badmodule(Tkclient->PATH); 57 tkclient->init(); 58 59 tk = load Tk Tk->PATH; 60 if (tk == nil) 61 badmodule(Tk->PATH); 62 63 arg := load Arg Arg->PATH; 64 if (arg == nil) 65 badmodule(Arg->PATH); 66 67 if (ctxt == nil) { 68 sys->fprint(stderr, "logwindow: nil Draw->Context\n"); 69 raise "fail:no draw context"; 70 } 71 gflag := 0; 72 title := "Log Window"; 73 arg->init(argv); 74 while ((opt := arg->opt()) != 0) { 75 case opt { 76 'e' => 77 eflag = 1; 78 'g' => 79 gflag = 1; 80 * => 81 sys->fprint(stderr, "usage: logwindow [-ge] [title]\n"); 82 raise "fail:usage"; 83 } 84 } 85 argv = arg->argv(); 86 if (argv != nil) 87 title = hd argv; 88 89 if (!gflag) 90 sys->pctl(Sys->NEWPGRP, nil); 91 92 (top, wmchan) := tkclient->toplevel(ctxt, "", title, Tkclient->Hide|Tkclient->Resize); 93 if (top == nil) { 94 sys->fprint(stderr, "logwindow: couldn't make window\n"); 95 raise "fail: no window"; 96 } 97 cmd(top, ". unmap"); 98 99 for (c:=0; c<len cfg; c++) 100 tk->cmd(top, cfg[c]); 101 if ((err := tk->cmd(top, "variable lasterror")) != nil) { 102 sys->fprint(stderr, "logwindow: tk error: %s\n", err); 103 raise "fail: tk error"; 104 } 105 106 logwin(sys->fildes(0), top, wmchan); 107} 108 109scrolling := 1; 110popup := 1; 111 112logwin(fd: ref Sys->FD, top: ref Tk->Toplevel, wmchan: chan of string) 113{ 114 cmd := chan of string; 115 tk->namechan(top, cmd, "cmd"); 116 raised := 0; 117 ichan := chan of int; 118 spawn inputmon(fd, top, ichan); 119 tkclient->onscreen(top, nil); 120 tkclient->startinput(top, "kbd"::"ptr"::nil); 121 tkclient->wmctl(top, "task"); 122 for (;;) alt { 123 s := <-top.ctxt.kbd => 124 tk->keyboard(top, s); 125 s := <-top.ctxt.ptr => 126 tk->pointer(top, *s); 127 s := <-top.ctxt.ctl or 128 s = <-top.wreq or 129 s = <-wmchan => 130 case s { 131 "task" => 132 raised = 0; 133 "untask" => 134 raised = 1; 135 } 136 tkclient->wmctl(top, s); 137 e := <-ichan => 138 if (e == 0 && eflag) { 139 tkclient->wmctl(top, "exit"); 140 exit; 141 } 142 if (!raised && popup) 143 tkclient->wmctl(top, "untask"); 144 msg := <-cmd => 145 case msg { 146 "scroll" => 147 scrolling = int tk->cmd(top, "variable scroll"); 148 "popup" => 149 popup = int tk->cmd(top, "variable popup"); 150 } 151 } 152} 153 154inputmon(fd: ref Sys->FD, top: ref Tk->Toplevel, ichan: chan of int) 155{ 156 buf := array[Sys->ATOMICIO] of byte; 157 t := 0; 158 while ((n := sys->read(fd, buf[t:], len buf-t)) > 0) { 159 t += n; 160 cl := 0; 161 for (i := t - 1; i >= 0; i--) { 162 (nil, cl, nil) = sys->byte2char(buf, i); 163 if (cl > 0) 164 break; 165 } 166 if (cl == 0) 167 continue; 168 logmsg(top, ichan, string buf[0:i+cl]); 169 buf[0:] = buf[i+cl:t]; 170 t -= i + cl; 171 } 172 if (n < 0) 173 logmsg(top, ichan, sys->sprint("Input error: %r\n")); 174 else 175 logmsg(top, ichan, "Got EOF\n"); 176 if (eflag) 177 ichan <-= 0; 178} 179 180logmsg(top: ref Tk->Toplevel, ichan: chan of int, m: string) 181{ 182 tk->cmd(top, ".t.t insert end '"+m); 183 if (scrolling) 184 tk->cmd(top, ".t.t see end"); 185 tk->cmd(top, "update"); 186 ichan <-= 1; 187} 188