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;
+ }
+ }
+}