ref: 345b8b783165ada4d53c50130fe2046e8627ea40
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;
if (!n)
return;
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;
}
}
}