ref: 1cc6b57271abaca8b8ac0c7c76a1f7cafe30068d
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Nov 18 09:08:20 EST 2020
first
--- /dev/null
+++ b/README.md
@@ -1,0 +1,6 @@
+# bar
+
+Displays battery, date and time in a small bar placed in the bottom
+right corner.
+
+![screenshot](scr.png)
--- /dev/null
+++ b/bar.c
@@ -1,0 +1,202 @@
+#include "theme.c"
+#include "nanosec.c"
+#include <keyboard.h>
+#include <mouse.h>
+
+#define MAX(a,b) ((a)>=(b)?(a):(b))
+#define MIN(a,b) ((a)<=(b)?(a):(b))
+#define CLAMP(x,min,max) MAX(min, MIN(max, x))
+
+enum {
+ Off = 4,
+};
+
+static Font *f;
+static struct {
+ int w, h;
+}scr;
+
+static char *wday[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
+static char *pos = "rb";
+static int wctl, width, bottom, bat;
+
+static void
+place(void)
+{
+ static int ow, oh;
+ char t[61], *a[5];
+ int f, n, w, h, minx, miny, maxx, maxy;
+
+ if((f = open("/dev/screen", OREAD)) < 0)
+ return;
+ n = read(f, t, sizeof(t)-1);
+ close(f);
+ 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){
+ if(pos[0] == 't' || pos[1] == 't'){
+ miny = 0;
+ maxy = 48;
+ }else{
+ miny = h-48;
+ maxy = h;
+ }
+ if(pos[0] == 'l' || pos[1] == 'l'){
+ minx = 0;
+ maxx = 4+width+4;
+ }else{
+ minx = w-4-width-4;
+ maxx = w;
+ }
+ fprint(wctl, "resize -r %d %d %d %d", minx, miny, maxx, maxy);
+ ow = w;
+ oh = h;
+ }
+}
+
+static void
+redraw(void)
+{
+ Tm *tm;
+ char bats[16], s[128], *t;
+ Point p;
+ Rectangle r;
+
+ lockdisplay(display);
+ r = screen->r;
+
+ draw(screen, r, colors[Dback].im, nil, ZP);
+
+ if(bat < 0 || pread(bat, bats, 4, 0) < 4)
+ bats[0] = 0;
+ else{
+ t = strchr(bats, ' ');
+ strcpy(t, "% | ");
+ }
+ tm = localtime(time(nil));
+ snprint(
+ s, sizeof(s),
+ "%s%04d/%02d/%02d %s %02d:%02d:%02d",
+ bats,
+ tm->year+1900, tm->mon+1, tm->mday,
+ wday[tm->wday],
+ tm->hour, tm->min, tm->sec
+ );
+ width = Off + stringwidth(f, s) + Off;
+ p.x = r.max.x - width + Off;
+ p.y = (pos[0] == 't' || pos[1] == 't') ? r.max.y - (f->height + Off) : r.min.y + Off;
+ string(screen, p, colors[Dfhigh].im, ZP, f, s);
+
+ flushimage(display, 1);
+ unlockdisplay(display);
+
+ place();
+}
+
+static void
+updateproc(void *)
+{
+ uvlong t, n;
+
+ t = nanosec();
+ for(;;){
+ sleep(250);
+ if(wctl < 0)
+ break;
+ fprint(wctl, bottom ? "bottom" : "top");
+ if((n = nanosec()) - t >= 1000000000ULL){
+ redraw();
+ t = n;
+ }
+ }
+
+ threadexits(nil);
+}
+
+void
+themechanged(void)
+{
+ redraw();
+}
+
+static void
+usage(void)
+{
+ fprint(2, "usage: %s [-b] [-p lt|rt|lb|rb]\n", argv0);
+ threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ Keyboardctl *kctl;
+ Mousectl *mctl;
+ Rune key;
+ Mouse m;
+ Alt a[] =
+ {
+ { nil, &m, CHANRCV },
+ { nil, nil, CHANRCV },
+ { nil, &key, CHANRCV },
+ { nil, nil, CHANEND },
+ };
+
+ ARGBEGIN{
+ case 'p':
+ pos = EARGF(usage());
+ break;
+ case 'b':
+ bottom = 1;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ 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;
+ unlockdisplay(display);
+ if((mctl = initmouse(nil, screen)) == nil)
+ sysfatal("initmouse: %r");
+ if((kctl = initkeyboard(nil)) == nil)
+ sysfatal("initkeyboard: %r");
+
+ a[0].c = mctl->c;
+ a[1].c = mctl->resizec;
+ a[2].c = kctl->c;
+
+ nanosec();
+ themeinit();
+ redraw();
+
+ proccreate(updateproc, nil, 4096);
+
+ for(;;){
+ redraw();
+
+ switch(alt(a)){
+ case 0:
+ break;
+
+ case 1:
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("getwindow: %r");
+ break;
+
+ case 2:
+ if(key == Kdel){
+ close(wctl);
+ wctl = -1;
+ threadexitsall(nil);
+ }
+ break;
+ }
+ }
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,11 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=bar
+HFILES=\
+ nanosec.c\
+ theme.c\
+
+default:V: all
+
+</sys/src/cmd/mkmany
--- /dev/null
+++ b/nanosec.c
@@ -1,0 +1,35 @@
+#include <tos.h>
+
+/*
+ * 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
+ */
+uvlong
+nanosec(void)
+{
+ static uvlong fasthz, xstart;
+ uvlong x, div;
+
+ if(fasthz == ~0ULL)
+ return nsec() - xstart;
+
+ if(fasthz == 0){
+ if((fasthz = _tos->cyclefreq) == 0){
+ fasthz = ~0ULL;
+ xstart = nsec();
+ fprint(2, "cyclefreq not available, falling back to nsec()\n");
+ fprint(2, "you might want to disable aux/timesync\n");
+ 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);
+}
binary files /dev/null b/scr.png differ
--- /dev/null
+++ b/theme.c
@@ -1,0 +1,162 @@
+#include <u.h>
+#include <libc.h>
+#include <plumb.h>
+#include <draw.h>
+#include <bio.h>
+#include <thread.h>
+#include "theme.h"
+
+ThemeColor colors[Numcolors] = {
+ [Dback] = {"background", 0x999999},
+ [Dfhigh] = {"f_high", 0xffffff},
+ [Dltitle] = {"ltitle", DPalegreygreen>>8},
+};
+
+void themechanged(void);
+
+static char *themeplumb;
+
+static void
+runpicker(void *x)
+{
+ int *p, f;
+ char tmp[32];
+
+ snprint(tmp, sizeof(tmp), "-pid %d -dx %d -dy %d", getpid(), 384, 320);
+ newwindow(tmp);
+
+ p = x;
+ dup(*p, 0); dup(*p, 1); close(*p);
+ close(p[1]);
+ close(p[2]);
+ dup(f = open("/dev/null", OWRITE), 2); close(f);
+ execl("/bin/picker", "picker", nil);
+
+ threadexits("exec: %r");
+}
+
+void
+themeproc(void *fd)
+{
+ Biobuf *b;
+ char *s, *v[3];
+ int p[3], n, i;
+ static int pid;
+
+ threadsetname("themeproc");
+ pipe(p);
+ p[2] = fd != nil ? *(int*)fd : -1;
+ postnote(PNGROUP, pid, "interrupt");
+ pid = threadpid(procrfork(runpicker, p, 4096, RFFDG|RFNAMEG|RFNOTEG));
+ close(p[0]);
+ b = Bfdopen(p[1], OREAD);
+
+ for(i = 0; i < nelem(colors); i++)
+ fprint(p[1], "%s\t%06ux\n", colors[i].id, colors[i].rgb);
+
+ for(;;){
+ if((s = Brdstr(b, '\n', 1)) == nil)
+ break;
+ if((n = tokenize(s, v, nelem(v))) >= 2){
+ for(i = 0; i < nelem(colors); i++){
+ if(strcmp(colors[i].id, v[0]) == 0){
+ if(display->locking)
+ lockdisplay(display);
+ freeimage(colors[i].im);
+ colors[i].rgb = strtoul(v[1], nil, 16);
+ colors[i].im = allocimage(display, Rect(0,0,1,1), RGB24, 1, colors[i].rgb<<8 | 0xff);
+ if(display->locking)
+ unlockdisplay(display);
+ themechanged();
+ break;
+ }
+ }
+ }
+ free(s);
+ if(n != 2)
+ break;
+ }
+ Bterm(b);
+ postnote(PNGROUP, pid, "interrupt");
+
+ threadexits(nil);
+}
+
+static int
+loadtheme(char *filename, int init)
+{
+ Biobuf *in;
+ char *s, *v[3];
+ int i, n;
+
+ if ((in = Bopen(filename, OREAD)) != nil) {
+ if(display->locking && !init)
+ lockdisplay(display);
+ for(;;){
+ if((s = Brdstr(in, '\n', 1)) == nil)
+ break;
+ if((n = tokenize(s, v, nelem(v))) == 2){
+ for(i = 0; i < nelem(colors); i++){
+ if(strcmp(colors[i].id, v[0]) == 0){
+ freeimage(colors[i].im);
+ colors[i].rgb = strtoul(v[1], nil, 16);
+ colors[i].im = allocimage(display, Rect(0,0,1,1), RGB24, 1, colors[i].rgb<<8 | 0xff);
+ break;
+ }
+ }
+ }
+ free(s);
+ if(n != 2)
+ break;
+ }
+ if(display->locking && !init)
+ unlockdisplay(display);
+ Bterm(in);
+ if(!init)
+ themechanged();
+ return 0;
+ }
+
+ return -1;
+}
+
+static void
+plumbproc(void *)
+{
+ int f;
+ Plumbmsg *m;
+
+ threadsetname("theme/plumb");
+ if ((f = plumbopen(themeplumb, OREAD)) >= 0) {
+ while ((m = plumbrecv(f)) != nil) {
+ loadtheme(m->data, 0);
+ themechanged();
+ plumbfree(m);
+ }
+ }
+
+ threadexits(nil);
+}
+
+void
+themeinit(void)
+{
+ char *s;
+ int i;
+
+ loadtheme("/dev/theme", 1);
+ colors[Dback].rgb = colors[Dltitle].rgb;
+ colors[Dfhigh].rgb = ~(colors[Dback].rgb | colors[Dback].rgb>>8 | colors[Dback].rgb>>16);
+
+ if((s = getenv("theme")) != nil){
+ if(loadtheme(s, 1) != 0)
+ sysfatal("theme load failed: %r");
+ free(s);
+ }
+ for(i = 0; i < Numcolors; i++){
+ if(colors[i].im == nil)
+ colors[i].im = allocimage(display, Rect(0,0,1,1), RGB24, 1, colors[i].rgb<<8 | 0xff);
+ }
+ if((themeplumb = getenv("themeplumb")) != nil)
+ proccreate(plumbproc, nil, 4096);
+}
--- /dev/null
+++ b/theme.h
@@ -1,0 +1,19 @@
+enum {
+ Dback = 0,
+ Dfhigh,
+ Dltitle,
+ Numcolors,
+};
+
+typedef struct ThemeColor ThemeColor;
+
+struct ThemeColor {
+ char *id;
+ u32int rgb;
+ Image *im;
+};
+
+extern ThemeColor colors[Numcolors];
+
+void themeproc(void *fd);
+void themeinit(void);