shithub: hours

Download patch

ref: 2eacf6036e4260756aa9923029719d9f32c5fdc0
parent: 1c1edbf0ca89d54abd729b6592892c00d8aec6d0
author: sirjofri <sirjofri@sirjofri.de>
date: Thu Nov 20 14:13:31 EST 2025

adds new watch program

--- a/mkfile
+++ b/mkfile
@@ -4,8 +4,16 @@
 files=hours.awk report clock watch
 
 install:V: ${files:%=$home/bin/rc/hours/%}
+	@{cd watch && mk install && cd ..}
 
 $home/bin/rc/hours/%: %
 	if(! test -d $home/bin/rc/hours)
 		mkdir $home/bin/rc/hours
 	cp $prereq $target
+
+$home/bin/rc/hours/watch:V:
+	cat <<! >$target
+	#!/bin/rc
+	exec $home/bin/$objtype/hours/watch
+	!
+	chmod +x $target
--- a/watch
+++ /dev/null
@@ -1,31 +1,0 @@
-#!/bin/rc
-
-rfork e
-clockfile=$home/lib/clocked_hour
-nl='
-'
-
-echo 'hours/watch' | tr -d $nl >/dev/label
-echo 'bottom' >/dev/wctl
-echo 'hide' >/dev/wctl
-
-fn loop{
-	if (! test -r $clockfile){
-		echo 'no clock is running'
-	}
-	if not{
-		data=`{cat $clockfile}
-		end=`{date -un}
-		start=$data(1)
-		td=`{echo $end - $start | hoc}
-		msg=$data(2-)
-		
-		hours=`{echo 'int(' $td / 3600 ')' | hoc}
-		min=`{echo 'int(int(' $td / 60 ')' % 60 ')' | hoc}
-		sec=`{echo $td % 60 | hoc}
-		
-		echo $hours^'h' $min^'m' $sec^'s' : $msg
-	}
-}
-
-@{while (sleep 1) loop} | aux/statusmsg
--- /dev/null
+++ b/watch/mkfile
@@ -1,0 +1,11 @@
+</$objtype/mkfile
+
+BIN=$home/bin/$objtype/hours
+TARG=watch
+OFILES=watch.$O
+
+</sys/src/cmd/mkone
+
+$BIN/$TARG: $O.out
+	mkdir -p `{basename -d $target}
+	cp $prereq $BIN/$TARG
--- /dev/null
+++ b/watch/watch.c
@@ -1,0 +1,269 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include <event.h>
+#include <keyboard.h>
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s\n", argv0);
+	exits("usage");
+}
+
+char *libhours = nil;
+char *watchfile = nil;
+
+char *message = nil;
+char *runtime = nil;
+
+int lineheight = 0;
+
+Image *playimg = nil;
+Image *stopimg = nil;
+
+Rectangle buttonbox;
+int timerrunning = 0;
+
+Point playps[] = {
+	{ 20, 20 },
+	{ 20, 80 },
+	{ 80, 50 },
+};
+
+Point stopps[] = {
+	{ 20, 20 },
+	{ 20, 80 },
+	{ 80, 80 },
+	{ 80, 20 },
+};
+
+void
+initimages(void)
+{
+	playimg = allocimage(display, Rect(0, 0, 100, 100), screen->chan, 0, DWhite);
+	stopimg = allocimage(display, Rect(0, 0, 100, 100), screen->chan, 0, DWhite);
+	
+	border(playimg, playimg->r, 1, display->black, ZP);
+	border(stopimg, stopimg->r, 1, display->black, ZP);
+	
+	fillpoly(playimg, playps, 3, 0, display->black, ZP);
+	fillpoly(stopimg, stopps, 4, 0, display->black, ZP);
+}
+
+void
+setmessage(char *s)
+{
+	if (message)
+		free(message);
+	message = s;
+}
+
+void
+setruntime(long tm)
+{
+	int hours, minutes, seconds;
+	
+	if (runtime)
+		free(runtime);
+	
+	hours = (int)(tm/3600);
+	minutes = (int)((tm/60)%60);
+	seconds = (int)(tm % 60);
+	
+	runtime = smprint("%dh %dm %ds", hours, minutes, seconds);
+}
+
+void
+redraw(void)
+{
+	Point p;
+	int x;
+	Image *todraw;
+	draw(screen, screen->r, display->white, nil, ZP);
+	
+	x = screen->r.min.x + 5;
+	p.y = screen->r.min.y + 5;
+	p.x = x;
+	
+	p = string(screen, p, display->black, ZP, font, runtime);
+	p.x = x;
+	p.y += lineheight;
+	p = string(screen, p, display->black, ZP, font, message);
+	
+	todraw = timerrunning ? stopimg : playimg;
+	
+	p.x = x;
+	p.y += lineheight;
+	buttonbox = rectaddpt(todraw->r, p);
+	draw(screen, buttonbox, todraw, nil, ZP);
+}
+
+long
+getstarttime(char **msg)
+{
+	Biobuf *bin;
+	char *s;
+	long t;
+	
+	bin = Bopen(watchfile, OREAD);
+	if (!bin)
+		return -1;
+	
+	s = Brdstr(bin, '\n', 1);
+	
+	*msg = strchr(s, '\t');
+	(*msg)++;
+	*msg = strdup(*msg);
+	t = atol(s);
+	free(s);
+	return t;
+}
+
+void
+update(void)
+{
+	char *msg;
+	long current, start;
+	
+	msg = nil;
+	start = getstarttime(&msg);
+	
+	if (start < 0) {
+		timerrunning = 0;
+		setmessage(strdup("no timer"));
+		setruntime(0);
+		redraw();
+		return;
+	}
+	
+	current = time(nil);
+	current -= start;
+	
+	timerrunning = 1;
+	setmessage(msg);
+	setruntime(current);
+	
+	redraw();
+}
+
+void
+stoptimer(void)
+{
+	int fd;
+	char *msg;
+	long start, current;
+	
+	fd = open(".hours", OWRITE);
+	if (fd < 0)
+		fd = open(libhours, OWRITE);
+	
+	if (fd < 0)
+		fd = create(libhours, OWRITE, 0666);
+	
+	if (fd < 0)
+		sysfatal("error accessing hours file: %r");
+	
+	msg = nil;
+	start = getstarttime(&msg);
+	if (start < 0)
+		return;
+	
+	current = time(nil);
+	
+	seek(fd, 0, 2);
+	fprint(fd, "%ld\t%ld\t%s\n", start, current, msg);
+	close(fd);
+	
+	remove(watchfile);
+}
+
+void
+starttimer(Mouse m)
+{
+	int fd;
+	long t;
+	char buf[1024];
+	
+	if (!access(watchfile, AEXIST))
+		return;
+	
+	fd = create(watchfile, OWRITE, 0666);
+	if (fd < 0)
+		sysfatal("create: %r");
+	
+	buf[0] = 0;
+	if (eenter("desc", buf, sizeof buf, &m) < 0)
+		return;
+	
+	t = time(nil);
+	
+	fprint(fd, "%ld\t%s\n", t, buf);
+	close(fd);
+}
+
+void
+mouseinput(Mouse m)
+{
+	if (m.buttons != 1)
+		return;
+	
+	if (ptinrect(m.xy, buttonbox)) {
+		if (timerrunning)
+			stoptimer();
+		else
+			starttimer(m);
+		update();
+		return;
+	}
+}
+
+void
+eresized(int new)
+{
+	if (new && getwindow(display, Refnone) < 0)
+		sysfatal("%r");
+	
+	redraw();
+}
+
+void
+main(int argc, char **argv)
+{
+	int e, timer;
+	Event ev;
+	
+	ARGBEGIN{
+	case 'h':
+		usage();
+	}ARGEND;
+	
+	if (initdraw(nil, nil, "hours/watch") < 0)
+		sysfatal("initdraw: %r");
+	initimages();
+	
+	einit(Emouse|Ekeyboard);
+	timer = etimer(0, 1000);
+	
+	watchfile = smprint("/usr/%s/lib/clocked_hour", getenv("user"));
+	libhours = smprint("/usr/%s/lib/hours", getenv("user"));
+	assert(watchfile && libhours);
+	
+	lineheight = stringsize(font, "M").y;
+	
+	for (;;) {
+		e = event(&ev);
+		switch (e) {
+		case Emouse:
+			mouseinput(ev.mouse);
+			break;
+		case Ekeyboard:
+			if (ev.kbdc == 'q' || ev.kbdc == Kdel)
+				exits(nil);
+			break;
+		}
+		if (e == timer)
+			update();
+	}
+}
--