shithub: notif

Download patch

ref: 40f17f0d981e7e96ff3cab4c6f9a38d357ab2222
author: sirjofri <sirjofri@sirjofri.de>
date: Thu Jan 20 14:22:59 EST 2022

adds files

--- /dev/null
+++ b/mkfile
@@ -1,0 +1,6 @@
+</$objtype/mkfile
+
+TARG=notif
+OFILES=notif.$O
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/notif.c
@@ -1,0 +1,281 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <event.h>
+#include <plumb.h>
+
+#define Eplumb 128
+
+typedef struct Notif Notif;
+struct Notif {
+	char *title;
+	char *message;
+	char *button;
+	char *cmd;
+	Plumbmsg *pmsg;
+	Rectangle r;
+	Notif *next;
+};
+
+Notif *notif = nil;
+
+Image* i_sep;
+Image* i_back;
+ulong c_sep = DGreyblue;
+ulong c_back = DWhite;
+Font *f_title;
+
+int
+initimages(void)
+{
+	i_sep = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, c_sep);
+	if (!i_sep) return -1;
+	
+	f_title = openfont(display, "/lib/font/bit/lucida/unicode.12.font");
+	if (!f_title) f_title = font;
+	
+	i_back = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, c_back);
+	if (!i_back) i_back = display->white;
+	return 0;
+}
+
+int
+drawnotif(Notif *n, Image *dst, Point p)
+{
+	Point ss;
+	int lpad = 8;
+	int i = 0;
+	Rectangle r;
+	r.min = p;
+	
+	if (n->title){
+		string(dst, addpt(p, Pt(lpad-2, i)), display->black, ZP,
+			f_title, n->title);
+		i += f_title->height;
+	}
+	
+	if (n->message){
+		i += 3;
+		string(dst, addpt(p, Pt(lpad, i)), i_sep, ZP, font, n->message);
+		i += font->height;
+	}
+	
+	if (n->button){
+		i += 3;
+		string(dst, addpt(p, Pt(lpad+3, i)), display->black, ZP,
+			font, n->button);
+		ss = stringsize(font, n->button);
+		border(dst,
+			rectaddpt(
+				Rpt(Pt(0, 0), addpt(ss, Pt(5, 0))),
+				addpt(p, Pt(lpad, i))),
+			-1, display->black, p);
+		i += font->height;
+	}
+	i += 5;
+	r.max = Pt(dst->r.max.x, p.y+i);
+	n->r = r;
+	return i;
+}
+
+int
+drawseparator(Image *dst, Point p)
+{
+	draw(dst, rectaddpt(Rect(0, 0, dst->r.max.x, 1), p),
+		i_sep, nil, ZP);
+	return 5;
+}
+
+void
+redraw(Image* screen)
+{
+	Notif *n = notif;
+	int i = 0;
+	
+	draw(screen, screen->r, i_back, nil, ZP);
+	
+	while (n) {
+		i += drawnotif(n, screen, addpt(screen->r.min, Pt(0, i)));
+		i += drawseparator(screen, addpt(screen->r.min, Pt(0, i)));
+		n = n->next;
+	}
+	
+	flushimage(display, 1);
+}
+
+void
+eresized(int new)
+{
+	if (new && getwindow(display, Refnone) < 0)
+		fprint(2, "can't reattach to window");
+	redraw(screen);
+}
+
+void
+addnotif(Notif *n)
+{
+	Notif *l;
+	
+	if (!n)
+		return;
+	
+	if (!notif) {
+		notif = n;
+		notif->next = nil;
+		return;
+	}
+	
+	l = notif;
+	while (l && l->next)
+		l = l->next;
+	
+	n->next = nil;
+	l->next = n;
+}
+
+Notif*
+crnotif(Plumbmsg *pm)
+{
+	char *msg;
+	char *title;
+	char *cmd;
+	char *btn;
+	Notif *n;
+	
+	msg = plumblookup(pm->attr, "message");
+	title = plumblookup(pm->attr, "title");
+	cmd = plumblookup(pm->attr, "cmd");
+	btn = plumblookup(pm->attr, "button");
+	
+	n = malloc(sizeof(Notif));
+	if (!n)
+		sysfatal("malloc: %r");
+	
+	n->message = msg;
+	n->title = title;
+	n->cmd = cmd;
+	n->button = btn;
+	n->pmsg = pm;
+	
+	return n;
+}
+
+Notif*
+getnotif(Point p)
+{
+	Notif *n;
+	n = notif;
+	
+	while (n) {
+		if (ptinrect(p, n->r))
+			return n;
+		n = n->next;
+	}
+	return nil;
+}
+
+void
+removenotify(Notif *n)
+{
+	Notif *p;
+	
+	if (!n)
+		return;
+	
+	p = notif;
+	
+	if (p == n){
+		notif = n->next;
+		goto Out;
+	}
+	
+	while (p && p->next != n)
+		p = p->next;
+	
+	if (!p)
+		return;
+	
+	p->next = n->next;
+Out:
+	plumbfree(n->pmsg);
+	free(n);
+	redraw(screen);
+}
+
+void
+execnotify(Notif *n)
+{
+	int fd;
+	char* wd = nil;
+	Plumbmsg *pmsg;
+	
+	fd = plumbopen("send", OWRITE);
+	if (fd < 0)
+		sysfatal("unable to open send channel: %r");
+	
+	if (n->cmd && strcmp(n->cmd, "") != 0){
+		if (n->pmsg)
+			wd = n->pmsg->wdir;
+		plumbsendtext(fd, "notif", nil, wd, n->cmd);
+		goto Out;
+	}
+	/* if no command given, assume data is a valid message */
+	if (n->pmsg && n->pmsg->data){
+		pmsg = plumbunpack(n->pmsg->data, n->pmsg->ndata);
+		if (pmsg)
+			plumbsend(fd, pmsg);
+		goto Out;
+	}
+	
+Out:
+	close(fd);
+}
+
+void
+main(int argc, char **argv)
+{
+	Event e;
+	Mouse m;
+	Plumbmsg *pm;
+	Notif *n;
+	
+	USED(argc, argv);
+	
+	if (initdraw(0, 0, "notif") < 0)
+		sysfatal("initdraw failed");
+	
+	if (initimages() < 0)
+		sysfatal("initimages failed");
+	
+	redraw(screen);
+	
+	einit(Emouse);
+	eplumb(Eplumb, "notify");
+	
+	for (;;){
+		switch (event(&e)){
+		case Emouse:
+			m = e.mouse;
+			if (m.buttons & 1){ // lmb, discard
+				n = getnotif(m.xy);
+				removenotify(n);
+				break;
+			}
+			else if (m.buttons & 4){ // rmb, execute
+				n = getnotif(m.xy);
+				execnotify(n);
+				removenotify(n);
+				break;
+			}
+			break;
+		case Eplumb:
+			pm = e.v;
+			if (pm->ndata == 0)
+				break;
+			n = crnotif(pm);
+			addnotif(n);
+			redraw(screen);
+			break;
+		}
+	}
+}