shithub: bar

Download patch

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);