ref: 9ed54083f5897ada0c46dca3be63bb139074fc0f
dir: /notif.c/
#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; } } }