Skip to content

Commit

Permalink
add support for tags and string output
Browse files Browse the repository at this point in the history
  • Loading branch information
phillbush committed Oct 27, 2020
1 parent 99187d5 commit 59cc5ff
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 55 deletions.
18 changes: 18 additions & 0 deletions xnotify.1
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ xnotify \- popup a notification on the screen
.RB [ \-o ]
.RB [ \-G
.IR gravity ]
.RB [ \-b
.IR button ]
.RB [ \-g
.IR geometry ]
.RB [ \-m
Expand All @@ -31,6 +33,14 @@ can be "NE" for NorthEastGravity (display on the top right corner of the screen)
"C" for CenterGravity (display on the center of the screen);
etc.
.TP
.BI "\-b " button
Specifies a number between 1 and 5 to be the mouse action button.
When clicking over a notification with the action button,
the notification will close,
and xnotify will output to its stdout the value of the notification's
.B CMD:
option.
.TP
.BI "\-g " geometry
Specifies the geometry in the form
.B [<WIDTH>x<HEIGHT>][{-+}<XOFFSET>{-+}<YOFFSET>].
Expand Down Expand Up @@ -95,6 +105,14 @@ The following names are currently accepted for the NAME:VALUE pairs:
.B IMG:
Specify the path of a image to be displayed on the notification.
.TP
.B TAG:
Specify a string to be the notification's tag.
When a notification with a given tag spawns,
all other notifications with the same tag disappears.
.TP
.B CMD:
Specify a string to be output when clicking on the notification with the action mouse button.
.TP
.B BG:
Specify the color of the notification background.
.TP
Expand Down
160 changes: 106 additions & 54 deletions xnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static int oflag = 0; /* whether only one notification must exist at a time */
void
usage(void)
{
(void)fprintf(stderr, "usage: xnotify [-o] [-G gravity] [-g geometry] [-m monitor] [-s seconds]\n");
(void)fprintf(stderr, "usage: xnotify [-o] [-G gravity] [-b button] [-g geometry] [-m monitor] [-s seconds]\n");
exit(1);
}

Expand Down Expand Up @@ -111,11 +111,34 @@ getoptions(int argc, char *argv[])
unsigned long n;
int ch;

while ((ch = getopt(argc, argv, "G:g:m:os:")) != -1) {
while ((ch = getopt(argc, argv, "G:b:g:m:os:")) != -1) {
switch (ch) {
case 'G':
config.gravityspec = optarg;
break;
case 'b':
if (*(optarg+1) != '\0')
break;
switch (*optarg) {
case '1':
config.actionbutton = Button1;
break;
case '2':
config.actionbutton = Button2;
break;
case '3':
config.actionbutton = Button3;
break;
case '4':
config.actionbutton = Button4;
break;
case '5':
config.actionbutton = Button5;
break;
default:
break;
}
break;
case 'g':
config.geometryspec = optarg;
break;
Expand Down Expand Up @@ -731,7 +754,7 @@ resettime(struct Item *item)

/* add item notification item and set its window and contents */
static void
additem(struct Queue *queue, const char *title, const char *body, const char *file, const char *background, const char *foreground, const char *border)
additem(struct Queue *queue, struct Itemspec *itemspec)
{
struct Item *item;
int titlew, bodyw;
Expand All @@ -740,9 +763,11 @@ additem(struct Queue *queue, const char *title, const char *body, const char *fi
if ((item = malloc(sizeof *item)) == NULL)
err(1, "malloc");
item->next = NULL;
item->title = strdup(title);
item->body = (body) ? strdup(body) : NULL;
item->image = (file) ? loadimage(file) : NULL;
item->title = strdup(itemspec->title);
item->body = (itemspec->body) ? strdup(itemspec->body) : NULL;
item->image = (itemspec->file) ? loadimage(itemspec->file) : NULL;
item->tag = (itemspec->tag) ? strdup(itemspec->tag) : NULL;
item->cmd = (itemspec->cmd) ? strdup(itemspec->cmd) : NULL;
if (!queue->head)
queue->head = item;
else
Expand All @@ -751,11 +776,11 @@ additem(struct Queue *queue, const char *title, const char *body, const char *fi
queue->tail = item;

/* allocate colors */
if (!background || ealloccolor(background, &item->background, 0) == -1)
if (!itemspec->background || ealloccolor(itemspec->background, &item->background, 0) == -1)
item->background = dc.background;
if (!foreground || ealloccolor(foreground, &item->foreground, 0) == -1)
if (!itemspec->foreground || ealloccolor(itemspec->foreground, &item->foreground, 0) == -1)
item->foreground = dc.foreground;
if (!border || ealloccolor(border, &item->border, 0) == -1)
if (!itemspec->border || ealloccolor(itemspec->border, &item->border, 0) == -1)
item->border = dc.border;

/* compute notification height */
Expand Down Expand Up @@ -824,73 +849,72 @@ optiontype(const char *s)
return FG;
if (strncmp(s, "BRD:", 4) == 0)
return BRD;
if (strncmp(s, "TAG:", 4) == 0)
return TAG;
if (strncmp(s, "CMD:", 4) == 0)
return CMD;
return UNKNOWN;
}

/* destroy all notification items */
static void
cleanitems(struct Queue *queue)
{
struct Item *item;
struct Item *tmp;

item = queue->head;
while (item) {
tmp = item;
item = item->next;
delitem(queue, tmp);
}
}

/* read stdin */
static void
parseinput(struct Queue *queue, char *s)
/* parse notification line */
static struct Itemspec *
parseline(char *s)
{
enum ItemOption option;
char *title, *body, *file, *fg, *bg, *brd;
struct Itemspec *itemspec;

if ((itemspec = malloc(sizeof *itemspec)) == NULL)
err(1, "malloc");

/* get the title */
title = strtok(s, "\t\n");
itemspec->title = strtok(s, "\t\n");

/* get the filename */
file = NULL;
fg = bg = brd = NULL;
while (title && (option = optiontype(title)) != UNKNOWN) {
itemspec->file = NULL;
itemspec->foreground = NULL;
itemspec->background = NULL;
itemspec->border = NULL;
itemspec->tag = NULL;
itemspec->cmd = NULL;
while (itemspec->title && (option = optiontype(itemspec->title)) != UNKNOWN) {
switch (option) {
case IMG:
file = title + 4;
title = strtok(NULL, "\t\n");
itemspec->file = itemspec->title + 4;
itemspec->title = strtok(NULL, "\t\n");
break;
case BG:
bg = title + 3;
title = strtok(NULL, "\t\n");
itemspec->background = itemspec->title + 3;
itemspec->title = strtok(NULL, "\t\n");
break;
case FG:
fg = title + 3;
title = strtok(NULL, "\t\n");
itemspec->foreground = itemspec->title + 3;
itemspec->title = strtok(NULL, "\t\n");
break;
case BRD:
brd = title + 4;
title = strtok(NULL, "\t\n");
itemspec->border = itemspec->title + 4;
itemspec->title = strtok(NULL, "\t\n");
break;
case TAG:
itemspec->tag = itemspec->title + 4;
itemspec->title = strtok(NULL, "\t\n");
case CMD:
itemspec->cmd = itemspec->title + 4;
itemspec->title = strtok(NULL, "\t\n");
default:
break;
}
}

/* get the body */
body = strtok(NULL, "\n");
if (body)
while (*body == '\t')
body++;
itemspec->body = strtok(NULL, "\n");
if (itemspec->body)
while (*itemspec->body == '\t')
itemspec->body++;

if (!title)
return;

if (oflag)
cleanitems(queue);
if (!itemspec->title)
return NULL;

additem(queue, title, body, file, bg, fg, brd);
return itemspec;
}

/* read x events */
Expand All @@ -907,8 +931,11 @@ readevent(struct Queue *queue)
copypixmap(item);
break;
case ButtonPress:
if ((item = getitem(queue, ev.xexpose.window)) != NULL)
delitem(queue, item);
if ((item = getitem(queue, ev.xbutton.window)) == NULL)
break;
if ((ev.xbutton.button == config.actionbutton) && item->cmd)
printf("%s\n", item->cmd);
delitem(queue, item);
break;
case MotionNotify:
if ((item = getitem(queue, ev.xmotion.window)) != NULL)
Expand Down Expand Up @@ -998,6 +1025,23 @@ moveitems(struct Queue *queue)
queue->change = 0;
}

/* destroy all notification items of the given tag, or all items if tag is NULL */
static void
cleanitems(struct Queue *queue, const char *tag)
{
struct Item *item;
struct Item *tmp;

item = queue->head;
while (item) {
tmp = item;
item = item->next;
if (tag == NULL || (tmp->tag && strcmp(tmp->tag, tag) == 0)) {
delitem(queue, tmp);
}
}
}

/* clean up dc elements */
static void
cleandc(void)
Expand All @@ -1015,6 +1059,7 @@ cleandc(void)
int
main(int argc, char *argv[])
{
struct Itemspec *itemspec;
struct Queue *queue; /* it contains the queue of notifications and their geometry */
struct pollfd pfd[2]; /* [2] for stdin and xfd, see poll(2) */
char buf[BUFSIZ]; /* buffer for stdin */
Expand Down Expand Up @@ -1076,7 +1121,14 @@ main(int argc, char *argv[])
if (pfd[0].revents & POLLIN) {
if (fgets(buf, sizeof buf, stdin) == NULL)
break;
parseinput(queue, buf);
if ((itemspec = parseline(buf)) != NULL) {
if (oflag) {
cleanitems(queue, NULL);
} else if (itemspec->tag) {
cleanitems(queue, itemspec->tag);
}
additem(queue, itemspec);
}
}
if (pfd[1].revents & POLLIN) {
readevent(queue);
Expand All @@ -1093,7 +1145,7 @@ main(int argc, char *argv[])
}

/* clean up stuff */
cleanitems(queue);
cleanitems(queue, NULL);
cleandc();
free(queue);

Expand Down
18 changes: 17 additions & 1 deletion xnotify.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
enum ItemOption {IMG, BG, FG, BRD, UNKNOWN};
enum ItemOption {IMG, BG, FG, BRD, TAG, CMD, UNKNOWN};
enum {DownWards, UpWards};
enum {LeftAlignment, CenterAlignment, RightAlignment};
enum {
Expand Down Expand Up @@ -32,6 +32,8 @@ struct Config {
int shrink;

int sec;

unsigned int actionbutton;
};

/* monitor geometry structure */
Expand All @@ -57,12 +59,26 @@ struct Fonts {
int texth; /* text height, also used for padding */
};

/* notification item specification structure */
struct Itemspec {
char *title;
char *body;
char *file;
char *background;
char *foreground;
char *border;
char *tag;
char *cmd;
};

/* notification item structure */
struct Item {
struct Item *prev, *next;

char *title;
char *body;
char *tag;
char *cmd;

time_t time;

Expand Down

0 comments on commit 59cc5ff

Please sign in to comment.