ref: 52eee1a7248f03b76d1599e1615510e4adfa5e4d
dir: /bar.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <keyboard.h>
#include <mouse.h>
#include <thread.h>
#include <tos.h>
#define MAX(a,b) ((a)>=(b)?(a):(b))
enum {
Off = 3,
};
static int wctl, owidth, width, twidth, bottom, bat, minheight;
static Image *cback, *ctext;
static char sep[16], bats[16], *aux;
static char *pos = "rb";
static Tzone *local;
static Font *f;
#pragma varargck type "|" char*
static int
sepfmt(Fmt *f)
{
return fmtstrcpy(f, va_arg(f->args, char*)[0] ? sep : "");
}
/*
* nsec() is wallclock and can be adjusted by timesync
* so need to use cycles() instead, but fall back to
* nsec() in case we can't
*/
static uvlong
nanosec(void)
{
static uvlong fasthz, xstart;
uvlong x, div;
if(fasthz == ~0ULL)
return nsec() - xstart;
if(fasthz == 0){
fasthz = _tos->cyclefreq;
if(fasthz == 0){
fasthz = ~0ULL;
xstart = nsec();
return 0;
}else{
cycles(&xstart);
}
}
cycles(&x);
x -= xstart;
/* this is ugly */
for(div = 1000000000ULL; x < 0x1999999999999999ULL && div > 1 ; div /= 10ULL, x *= 10ULL);
return x / (fasthz / div);
}
static void
place(void)
{
int fd, n, w, h, minx, miny, maxx, maxy;
char t[61], *a[5];
static int ow, oh;
if((fd = open("/dev/screen", OREAD)) < 0)
return;
n = read(fd, t, sizeof(t)-1);
close(fd);
t[sizeof(t)-1] = 0;
if(n != sizeof(t)-1 || tokenize(t, a, 5) != 5)
return;
w = atoi(a[3]);
h = atoi(a[4]);
if(ow != w || oh != h || owidth != width){
if(pos[0] == 't' || pos[1] == 't'){
miny = 0;
maxy = minheight;
}else{
miny = h - minheight;
maxy = h;
}
if(pos[0] == 'l' || pos[1] == 'l'){
minx = 0;
maxx = MAX(100, Borderwidth+Off+width+Off+Borderwidth);
}else if(pos[0] == 'r' || pos[1] == 'r'){
minx = MAX(100, w-(Borderwidth+Off+width+Off+Borderwidth));
maxx = w;
}else{
minx = (w-MAX(100, Borderwidth+Off+width+Off+Borderwidth))/2;
maxx = (w+MAX(100, Borderwidth+Off+width+Off+Borderwidth))/2;
}
snprint(t, sizeof(t), "resize -r %d %d %d %d", minx, miny, maxx, maxy);
if(fprint(wctl, "%s", t) < 0)
fprint(2, "%s: %r\n", t);
ow = w;
oh = h;
owidth = width;
}
}
static void
redraw(void)
{
char s[128];
Rectangle r;
Tmfmt tf;
Point p;
Tm tm;
lockdisplay(display);
r = screen->r;
draw(screen, r, cback, nil, ZP);
tf = tmfmt(tmnow(&tm, local), "YYYY/MM/DD WW hh:mm:ss");
p.x = r.min.x + Off;
p.y = (pos[0] == 't' || pos[1] == 't') ? r.max.y - (f->height + Off) : r.min.y + Off;
if(pos[0] == 'l' || pos[1] == 'l'){
snprint(s, sizeof(s), "%τ%|%s%|%s", tf, bats, bats, aux, aux);
}else{
snprint(s, sizeof(s), "%s%|%s%|%τ", aux, aux, bats, bats, tf);
if(pos[0] == 'r' || pos[1] == 'r')
p.x = r.max.x - (stringwidth(f, s) + Off);
}
string(screen, p, ctext, ZP, f, s);
flushimage(display, 1);
unlockdisplay(display);
snprint(s, sizeof(s), "%τ", tf);
twidth = MAX(twidth, stringwidth(f, s));
snprint(s, sizeof(s), "%|%s%|%s", bats, bats[0] ? "100%" : "", aux, aux);
width = twidth + stringwidth(f, s);
if(owidth != width)
place();
}
static void
readbattery(void)
{
char *s, tmp[16];
s = bat < 0 || pread(bat, tmp, 4, 0) < 4 ? nil : strchr(tmp, ' ');
if(s != nil){
*s = 0;
snprint(bats, sizeof(bats), "%s%%", tmp);
}else{
bats[0] = 0;
}
}
static void
updateproc(void *)
{
uvlong t1, t2, n;
t1 = nanosec();
t2 = t1;
for(;;){
sleep(250);
if(wctl < 0)
break;
fprint(wctl, bottom ? "bottom" : "top");
n = nanosec();
if(n - t1 >= 10000000000ULL){
readbattery();
t1 = n;
}
if(n - t2 >= 1000000000ULL){
redraw();
t2 = n;
}
}
threadexits(nil);
}
static void
auxproc(void *c)
{
Biobuf b;
char *s;
Binit(&b, 0, OREAD);
for(;;){
s = Brdstr(&b, '\n', 1);
sendp(c, s);
if(s == nil)
break;
}
Bterm(&b);
threadexits(nil);
}
static void
usage(void)
{
fprint(2, "usage: %s [-b] [-p lt|t|rt|lb|b|rb] [-s separator]\n", argv0);
threadexitsall("usage");
}
void
threadmain(int argc, char **argv)
{
Keyboardctl *kctl;
Mousectl *mctl;
char *s, *v[3];
u32int brgb;
Biobuf *b;
Rune key;
Mouse m;
enum {
Emouse,
Eresize,
Ekeyboard,
Eaux,
Eend,
};
Alt a[] = {
[Emouse] = { nil, &m, CHANRCV },
[Eresize] = { nil, nil, CHANRCV },
[Ekeyboard] = { nil, &key, CHANRCV },
[Eaux] = { nil, &s, CHANRCV },
[Eend] = { nil, nil, CHANEND },
};
strcpy(sep, " │ ");
ARGBEGIN{
case 'b':
bottom = 1;
break;
case 'p':
pos = EARGF(usage());
break;
case 's':
snprint(sep, sizeof(sep), "%s", EARGF(usage()));
break;
default:
usage();
}ARGEND
fmtinstall('|', sepfmt);
tmfmtinstall();
if((local = tzload("local")) == nil)
sysfatal("zone: %r");
if((wctl = open("/dev/wctl", ORDWR)) < 0)
sysfatal("%r");
bat = open("/mnt/acpi/battery", OREAD);
if(initdraw(nil, nil, "bar") < 0)
sysfatal("initdraw: %r");
f = display->defaultfont;
minheight = 2*(Borderwidth+1) + f->height;
unlockdisplay(display);
if((mctl = initmouse(nil, screen)) == nil)
sysfatal("initmouse: %r");
if((kctl = initkeyboard(nil)) == nil)
sysfatal("initkeyboard: %r");
a[Emouse].c = mctl->c;
a[Eresize].c = mctl->resizec;
a[Ekeyboard].c = kctl->c;
a[Eaux].c = chancreate(sizeof(s), 4);
brgb = DPalegreygreen;
if((b = Bopen("/dev/theme", OREAD)) != nil){
while((s = Brdline(b, '\n')) != nil){
s[Blinelen(b)-1] = 0;
if(tokenize(s, v, nelem(v)) > 1 && strcmp(v[0], "ltitle") == 0){
brgb = strtoul(v[1], nil, 16)<<8 | 0xff;
break;
}
}
Bterm(b);
}
cback = allocimage(display, Rect(0,0,1,1), RGB24, 1, brgb);
brgb = ~(brgb>>8 | brgb>>16 | brgb>>24);
brgb = brgb<<8 | brgb<<16 | brgb<<24 | 0xff;
ctext = allocimage(display, Rect(0,0,1,1), RGB24, 1, brgb);
aux = strdup("");
readbattery();
redraw();
proccreate(updateproc, nil, 4096);
proccreate(auxproc, a[Eaux].c, 16384);
for(;;){
switch(alt(a)){
case Emouse:
break;
case Ekeyboard:
if(key == Kdel){
close(wctl);
wctl = -1;
threadexitsall(nil);
}
break;
case Eresize:
if(getwindow(display, Refnone) < 0)
threadexitsall(nil);
/* wet floor */
case Eaux:
if(wctl >= 0)
fprint(wctl, bottom ? "bottom" : "top");
free(aux);
aux = strdup(s ? s : "");
redraw();
place();
break;
}
}
}