xref: /plan9/sys/src/cmd/aux/statusbar.c (revision e06f534bbaa4097bc6f4764ef1dd2dc3338fbd40)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <bio.h>
5 #include <event.h>
6 
7 enum {PNCTL=3};
8 
9 static char* rdenv(char*);
10 int newwin(char*);
11 Rectangle screenrect(void);
12 
13 int nokill;
14 int textmode;
15 char *title;
16 
17 Image *light;
18 Image *dark;
19 Image *text;
20 
21 void
22 initcolor(void)
23 {
24 	text = display->black;
25 	light = allocimagemix(display, DPalegreen, DWhite);
26 	dark = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen);
27 }
28 
29 Rectangle rbar;
30 Point ptext;
31 vlong n, d;
32 int last;
33 int lastp = -1;
34 
35 char backup[80];
36 
37 void
38 drawbar(void)
39 {
40 	int i, j;
41 	int p;
42 	char buf[400], bar[200];
43 	static char lastbar[200];
44 
45 	if(n > d || n < 0 || d <= 0)
46 		return;
47 
48 	i = (Dx(rbar)*n)/d;
49 	p = (n*100LL)/d;
50 
51 	if(textmode){
52 		if(Dx(rbar) > 150){
53 			rbar.min.x = 0;
54 			rbar.max.x = 150;
55 			return;
56 		}
57 		bar[0] = '|';
58 		for(j=0; j<i; j++)
59 			bar[j+1] = '#';
60 		for(; j<Dx(rbar); j++)
61 			bar[j+1] = '-';
62 		bar[j++] = '|';
63 		bar[j++] = ' ';
64 		sprint(bar+j, "%3d%% ", p);
65 		for(i=0; bar[i]==lastbar[i] && bar[i]; i++)
66 			;
67 		memset(buf, '\b', strlen(lastbar)-i);
68 		strcpy(buf+strlen(lastbar)-i, bar+i);
69 		if(buf[0])
70 			write(1, buf, strlen(buf));
71 		strcpy(lastbar, bar);
72 		return;
73 	}
74 
75 	if(lastp == p && last == i)
76 		return;
77 
78 	if(lastp != p){
79 		sprint(buf, "%d%%", p);
80 
81 		stringbg(screen, addpt(screen->r.min, Pt(Dx(rbar)-30, 4)), text, ZP, display->defaultfont, buf, light, ZP);
82 		lastp = p;
83 	}
84 
85 	if(last != i){
86 		draw(screen, Rect(rbar.min.x+last, rbar.min.y, rbar.min.x+i, rbar.max.y),
87 			dark, nil, ZP);
88 		last = i;
89 	}
90 	flushimage(display, 1);
91 }
92 
93 void
94 eresized(int new)
95 {
96 	Point p, q;
97 	Rectangle r;
98 
99 	if(new && getwindow(display, Refnone) < 0)
100 		fprint(2,"can't reattach to window");
101 
102 	r = screen->r;
103 	draw(screen, r, light, nil, ZP);
104 	p = string(screen, addpt(r.min, Pt(4,4)), text, ZP,
105 		display->defaultfont, title);
106 
107 	p.x = r.min.x+4;
108 	p.y += display->defaultfont->height+4;
109 
110 	q = subpt(r.max, Pt(4,4));
111 	rbar = Rpt(p, q);
112 
113 	ptext = Pt(r.max.x-4-stringwidth(display->defaultfont, "100%"), r.min.x+4);
114 	border(screen, rbar, -2, dark, ZP);
115 	last = 0;
116 	lastp = -1;
117 
118 	drawbar();
119 }
120 
121 void
122 bar(Biobuf *b)
123 {
124 	char *p, *f[2];
125 	Event e;
126 	int k, die, parent, child;
127 
128 	parent = getpid();
129 
130 	die = 0;
131 	if(textmode)
132 		child = -1;
133 	else
134 	switch(child = rfork(RFMEM|RFPROC)) {
135 	case 0:
136 		sleep(1000);
137 		while(!die && (k = eread(Ekeyboard|Emouse, &e))) {
138 			if(nokill==0 && k == Ekeyboard && (e.kbdc == 0x7F || e.kbdc == 0x03)) { /* del, ctl-c */
139 				die = 1;
140 				postnote(PNPROC, parent, "interrupt");
141 				_exits("interrupt");
142 			}
143 		}
144 		_exits(0);
145 	}
146 
147 	while(!die && (p = Brdline(b, '\n'))) {
148 		p[Blinelen(b)-1] = '\0';
149 		if(tokenize(p, f, 2) != 2)
150 			continue;
151 		n = strtoll(f[0], 0, 0);
152 		d = strtoll(f[1], 0, 0);
153 		drawbar();
154 	}
155 	postnote(PNCTL, child, "kill");
156 }
157 
158 
159 void
160 usage(void)
161 {
162 	fprint(2, "usage: aux/statusbar [-kt] [-w minx,miny,maxx,maxy] 'title'\n");
163 	exits("usage");
164 }
165 
166 void
167 main(int argc, char **argv)
168 {
169 	Biobuf b;
170 	char *p, *q;
171 	int lfd;
172 
173 	p = "0,0,200,60";
174 
175 	ARGBEGIN{
176 	case 'w':
177 		p = ARGF();
178 		break;
179 	case 't':
180 		textmode = 1;
181 		break;
182 	case 'k':
183 		nokill = 1;
184 		break;
185 	default:
186 		usage();
187 	}ARGEND;
188 
189 	if(argc != 1)
190 		usage();
191 
192 	title = argv[0];
193 
194 	lfd = dup(0, -1);
195 
196 	while(q = strchr(p, ','))
197 		*q = ' ';
198 	Binit(&b, lfd, OREAD);
199 	if(textmode || newwin(p) < 0){
200 		textmode = 1;
201 		rbar = Rect(0, 0, 60, 1);
202 	}else{
203 		if(initdraw(0, 0, "bar") < 0)
204 			exits("initdraw");
205 		initcolor();
206 		einit(Emouse|Ekeyboard);
207 		eresized(0);
208 	}
209 	bar(&b);
210 
211 	exits(0);
212 }
213 
214 
215 /* all code below this line should be in the library, but is stolen from colors instead */
216 static char*
217 rdenv(char *name)
218 {
219 	char *v;
220 	int fd, size;
221 
222 	fd = open(name, OREAD);
223 	if(fd < 0)
224 		return 0;
225 	size = seek(fd, 0, 2);
226 	v = malloc(size+1);
227 	if(v == 0){
228 		fprint(2, "%s: can't malloc: %r\n", argv0);
229 		exits("no mem");
230 	}
231 	seek(fd, 0, 0);
232 	read(fd, v, size);
233 	v[size] = 0;
234 	close(fd);
235 	return v;
236 }
237 
238 int
239 newwin(char *win)
240 {
241 	char *srv, *mntsrv;
242 	char spec[100];
243 	int srvfd, cons, pid;
244 
245 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){
246 	case -1:
247 		fprint(2, "statusbar: can't fork: %r\n");
248 		return -1;
249 	case 0:
250 		break;
251 	default:
252 		exits(0);
253 	}
254 
255 	srv = rdenv("/env/wsys");
256 	if(srv == 0){
257 		mntsrv = rdenv("/mnt/term/env/wsys");
258 		if(mntsrv == 0){
259 			fprint(2, "statusbar: can't find $wsys\n");
260 			return -1;
261 		}
262 		srv = malloc(strlen(mntsrv)+10);
263 		sprint(srv, "/mnt/term%s", mntsrv);
264 		free(mntsrv);
265 		pid  = 0;			/* can't send notes to remote processes! */
266 	}else
267 		pid = getpid();
268 	USED(pid);
269 	srvfd = open(srv, ORDWR);
270 	free(srv);
271 	if(srvfd == -1){
272 		fprint(2, "statusbar: can't open %s: %r\n", srv);
273 		return -1;
274 	}
275 	sprint(spec, "new -r %s", win);
276 	if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){
277 		fprint(2, "statusbar: can't mount /mnt/wsys: %r (spec=%s)\n", spec);
278 		return -1;
279 	}
280 	close(srvfd);
281 	unmount("/mnt/acme", "/dev");
282 	bind("/mnt/wsys", "/dev", MBEFORE);
283 	cons = open("/dev/cons", OREAD);
284 	if(cons==-1){
285 	NoCons:
286 		fprint(2, "statusbar: can't open /dev/cons: %r");
287 		return -1;
288 	}
289 	dup(cons, 0);
290 	close(cons);
291 	cons = open("/dev/cons", OWRITE);
292 	if(cons==-1)
293 		goto NoCons;
294 	dup(cons, 1);
295 	dup(cons, 2);
296 	close(cons);
297 //	wctlfd = open("/dev/wctl", OWRITE);
298 	return 0;
299 }
300 
301 Rectangle
302 screenrect(void)
303 {
304 	int fd;
305 	char buf[12*5];
306 
307 	fd = open("/dev/screen", OREAD);
308 	if(fd == -1)
309 		fd=open("/mnt/term/dev/screen", OREAD);
310 	if(fd == -1){
311 		fprint(2, "%s: can't open /dev/screen: %r\n", argv0);
312 		exits("window read");
313 	}
314 	if(read(fd, buf, sizeof buf) != sizeof buf){
315 		fprint(2, "%s: can't read /dev/screen: %r\n", argv0);
316 		exits("screen read");
317 	}
318 	close(fd);
319 	return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48));
320 }
321 
322 int
323 postnote(int group, int pid, char *note)
324 {
325 	char file[128];
326 	int f, r;
327 
328 	switch(group) {
329 	case PNPROC:
330 		sprint(file, "/proc/%d/note", pid);
331 		break;
332 	case PNGROUP:
333 		sprint(file, "/proc/%d/notepg", pid);
334 		break;
335 	case PNCTL:
336 		sprint(file, "/proc/%d/ctl", pid);
337 		break;
338 	default:
339 		return -1;
340 	}
341 
342 	f = open(file, OWRITE);
343 	if(f < 0)
344 		return -1;
345 
346 	r = strlen(note);
347 	if(write(f, note, r) != r) {
348 		close(f);
349 		return -1;
350 	}
351 	close(f);
352 	return 0;
353 }
354