xref: /inferno-os/appl/wm/logwindow.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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