Merge branch 'master' of github.com:knopwob/dunst
This commit is contained in:
commit
eb5e8fb537
6
Makefile
6
Makefile
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
include config.mk
|
include config.mk
|
||||||
|
|
||||||
SRC = draw.c dunst.c list.c dunst_dbus.c ini.c utils.c
|
SRC = draw.c dunst.c list.c dunst_dbus.c utils.c options.c
|
||||||
OBJ = ${SRC:.c=.o}
|
OBJ = ${SRC:.c=.o}
|
||||||
|
|
||||||
all: doc options dunst service
|
all: doc options dunst service
|
||||||
@ -24,9 +24,9 @@ config.h:
|
|||||||
@echo creating $@ from config.def.h
|
@echo creating $@ from config.def.h
|
||||||
@cp config.def.h $@
|
@cp config.def.h $@
|
||||||
|
|
||||||
dunst: draw.o dunst.o list.o dunst_dbus.o ini.o utils.o
|
dunst: draw.o dunst.o list.o dunst_dbus.o utils.o options.o
|
||||||
@echo CC -o $@
|
@echo CC -o $@
|
||||||
@${CC} ${CFLAGS} -o $@ dunst.o draw.o list.o dunst_dbus.o ini.o utils.o ${LDFLAGS}
|
@${CC} ${CFLAGS} -o $@ dunst.o draw.o list.o dunst_dbus.o options.o utils.o ${LDFLAGS}
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@echo cleaning
|
@echo cleaning
|
||||||
|
@ -119,6 +119,8 @@ fmt is a string containing placeholders. The placeholders will be replaced with
|
|||||||
|
|
||||||
=item B<%I> iconname (without its path)
|
=item B<%I> iconname (without its path)
|
||||||
|
|
||||||
|
=item B<%p> progress value ([ 0%] to [100%])
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 COLORS
|
=head1 COLORS
|
||||||
@ -131,6 +133,7 @@ X color names.
|
|||||||
|
|
||||||
dunst is able to get different colors for a message via notify-send.
|
dunst is able to get different colors for a message via notify-send.
|
||||||
In order to do that you have to add a hint via the -h option.
|
In order to do that you have to add a hint via the -h option.
|
||||||
|
The progress value can be set with a hint, too.
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
@ -138,6 +141,8 @@ In order to do that you have to add a hint via the -h option.
|
|||||||
|
|
||||||
=item notify-send -h string:bgcolor:#4444ff -h string:fgcolor:#ff4444
|
=item notify-send -h string:bgcolor:#4444ff -h string:fgcolor:#ff4444
|
||||||
|
|
||||||
|
=item notify-send -h int:value:42 "Working ..."
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 CONFIGURATION
|
=head1 CONFIGURATION
|
||||||
|
401
dunst.c
401
dunst.c
@ -27,9 +27,12 @@
|
|||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "dunst_dbus.h"
|
#include "dunst_dbus.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "ini.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
#ifndef STATIC_CONFIG
|
||||||
|
#include "options.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh))
|
#define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh))
|
||||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
@ -185,14 +188,15 @@ void warn(const char *text, int urg)
|
|||||||
if (n == NULL)
|
if (n == NULL)
|
||||||
die("Unable to allocate memory", EXIT_FAILURE);
|
die("Unable to allocate memory", EXIT_FAILURE);
|
||||||
|
|
||||||
n->appname = "dunst";
|
n->appname = strdup("dunst");
|
||||||
n->summary = strdup(text);
|
n->summary = strdup(text);
|
||||||
if (n->summary == NULL)
|
if (n->summary == NULL)
|
||||||
die("Unable to allocate memory", EXIT_FAILURE);
|
die("Unable to allocate memory", EXIT_FAILURE);
|
||||||
n->body = "";
|
n->body = strdup("");
|
||||||
n->icon = "";
|
n->icon = strdup("");
|
||||||
n->timeout = 0;
|
n->timeout = 0;
|
||||||
n->urgency = urg;
|
n->urgency = urg;
|
||||||
|
n->progress = 0;
|
||||||
n->dbus_client = NULL;
|
n->dbus_client = NULL;
|
||||||
n->color_strings[ColFG] = NULL;
|
n->color_strings[ColFG] = NULL;
|
||||||
n->color_strings[ColBG] = NULL;
|
n->color_strings[ColBG] = NULL;
|
||||||
@ -338,7 +342,12 @@ void update_lists()
|
|||||||
}
|
}
|
||||||
|
|
||||||
to_move = most_important(notification_queue);
|
to_move = most_important(notification_queue);
|
||||||
|
if (!to_move) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
n = (notification *) to_move->data;
|
n = (notification *) to_move->data;
|
||||||
|
if (!n)
|
||||||
|
return;
|
||||||
n->start = now;
|
n->start = now;
|
||||||
|
|
||||||
/* TODO get notifications pushed back into
|
/* TODO get notifications pushed back into
|
||||||
@ -357,7 +366,7 @@ void update_lists()
|
|||||||
int do_word_wrap(char *source, int max_width)
|
int do_word_wrap(char *source, int max_width)
|
||||||
{
|
{
|
||||||
|
|
||||||
strtrim_end(source);
|
rstrip(source);
|
||||||
|
|
||||||
if (!source || strlen(source) == 0)
|
if (!source || strlen(source) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -402,39 +411,30 @@ int do_word_wrap(char *source, int max_width)
|
|||||||
|
|
||||||
void update_draw_txt_buf(notification * n, int max_width)
|
void update_draw_txt_buf(notification * n, int max_width)
|
||||||
{
|
{
|
||||||
strtrim_end(n->msg);
|
rstrip(n->msg);
|
||||||
char *msg = n->msg;
|
char *msg = n->msg;
|
||||||
while(isspace(*msg))
|
while(isspace(*msg))
|
||||||
msg++;
|
msg++;
|
||||||
|
|
||||||
if (!n->draw_txt_buf.txt) {
|
if (n->draw_txt_buf.txt)
|
||||||
int dup_len = strlen(" () ") + digit_count(INT_MAX);
|
free(n->draw_txt_buf.txt);
|
||||||
int msg_len = strlen(msg) + 2; /* 2 == surrounding spaces */
|
|
||||||
int age_len = strlen(" ( h 60m 60s old ) ")
|
|
||||||
+ digit_count(INT_MAX); /* could be INT_MAX hours */
|
|
||||||
int line_length = dup_len + msg_len + age_len;
|
|
||||||
|
|
||||||
line_length += sizeof(" ( more ) ") + digit_count(INT_MAX);
|
char *buf;
|
||||||
|
|
||||||
n->draw_txt_buf.txt = calloc(line_length, sizeof(char));
|
|
||||||
n->draw_txt_buf.bufsize = line_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *buf = n->draw_txt_buf.txt;
|
|
||||||
int bufsize = n->draw_txt_buf.bufsize;
|
|
||||||
char *next = buf;
|
|
||||||
|
|
||||||
memset(buf, '\0', bufsize);
|
|
||||||
|
|
||||||
/* print dup_count */
|
/* print dup_count */
|
||||||
if (n->dup_count > 0) {
|
if (n->dup_count > 0) {
|
||||||
snprintf(next, bufsize - strlen(buf), "(%d) ", n->dup_count);
|
asprintf(&buf, "(%d)", n->dup_count);
|
||||||
next = buf + strlen(buf);
|
} else {
|
||||||
|
buf = strdup("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print msg */
|
/* print msg */
|
||||||
strncat(buf, msg, bufsize - strlen(buf));
|
{
|
||||||
next = buf + strlen(buf);
|
char *new_buf;
|
||||||
|
asprintf(&new_buf, "%s %s", buf, msg);
|
||||||
|
free(buf);
|
||||||
|
buf = new_buf;
|
||||||
|
}
|
||||||
|
|
||||||
/* print age */
|
/* print age */
|
||||||
int hours, minutes, seconds;
|
int hours, minutes, seconds;
|
||||||
@ -445,20 +445,22 @@ void update_draw_txt_buf(notification * n, int max_width)
|
|||||||
minutes = t_delta / 60 % 60;
|
minutes = t_delta / 60 % 60;
|
||||||
seconds = t_delta % 60;
|
seconds = t_delta % 60;
|
||||||
|
|
||||||
|
char *new_buf;
|
||||||
if (hours > 0) {
|
if (hours > 0) {
|
||||||
snprintf(next, bufsize - strlen(buf),
|
asprintf(&new_buf, "%s (%dh %dm %ds old)", buf, hours,
|
||||||
" (%dh %dm %ds old)", hours, minutes, seconds);
|
minutes, seconds);
|
||||||
} else if (minutes > 0) {
|
} else if (minutes > 0) {
|
||||||
snprintf(next, bufsize - strlen(buf), " (%dm %ds old)",
|
asprintf(&new_buf, "%s (%dm %ds old)", buf, minutes, seconds);
|
||||||
minutes, seconds);
|
|
||||||
} else {
|
} else {
|
||||||
snprintf(next, bufsize - strlen(buf), " (%ds old)",
|
asprintf(&new_buf, "%s (%ds old)", buf, seconds);
|
||||||
seconds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
buf = new_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
n->draw_txt_buf.line_count =
|
n->draw_txt_buf.line_count = do_word_wrap(buf, max_width);
|
||||||
do_word_wrap(n->draw_txt_buf.txt, max_width);
|
n->draw_txt_buf.txt = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *draw_txt_get_line(draw_txt * dt, int line)
|
char *draw_txt_get_line(draw_txt * dt, int line)
|
||||||
@ -907,6 +909,13 @@ int init_notification(notification * n, int id)
|
|||||||
n->msg = string_replace("%i", n->icon, n->msg);
|
n->msg = string_replace("%i", n->icon, n->msg);
|
||||||
n->msg = string_replace("%I", basename(n->icon), n->msg);
|
n->msg = string_replace("%I", basename(n->icon), n->msg);
|
||||||
n->msg = string_replace("%b", n->body, n->msg);
|
n->msg = string_replace("%b", n->body, n->msg);
|
||||||
|
if (n->progress) {
|
||||||
|
char pg[10];
|
||||||
|
sprintf(pg, "[%3d%%]", n->progress-1);
|
||||||
|
n->msg = string_replace("%p", pg, n->msg);
|
||||||
|
} else {
|
||||||
|
n->msg = string_replace("%p", "", n->msg);
|
||||||
|
}
|
||||||
|
|
||||||
n->msg = fix_markup(n->msg);
|
n->msg = fix_markup(n->msg);
|
||||||
|
|
||||||
@ -917,7 +926,7 @@ int init_notification(notification * n, int id)
|
|||||||
/* check if n is a duplicate */
|
/* check if n is a duplicate */
|
||||||
for (l_node * iter = notification_queue->head; iter; iter = iter->next) {
|
for (l_node * iter = notification_queue->head; iter; iter = iter->next) {
|
||||||
notification *orig = (notification *) iter->data;
|
notification *orig = (notification *) iter->data;
|
||||||
if (strcmp(orig->msg, n->msg) == 0) {
|
if (strcmp(orig->appname, n->appname) == 0 && strcmp(orig->msg, n->msg) == 0) {
|
||||||
orig->dup_count++;
|
orig->dup_count++;
|
||||||
free_notification(n);
|
free_notification(n);
|
||||||
return orig->id;
|
return orig->id;
|
||||||
@ -927,7 +936,7 @@ int init_notification(notification * n, int id)
|
|||||||
for (l_node * iter = displayed_notifications->head; iter;
|
for (l_node * iter = displayed_notifications->head; iter;
|
||||||
iter = iter->next) {
|
iter = iter->next) {
|
||||||
notification *orig = (notification *) iter->data;
|
notification *orig = (notification *) iter->data;
|
||||||
if (strcmp(orig->msg, n->msg) == 0) {
|
if (strcmp(orig->appname, n->appname) == 0 && strcmp(orig->msg, n->msg) == 0) {
|
||||||
orig->dup_count++;
|
orig->dup_count++;
|
||||||
orig->start = now;
|
orig->start = now;
|
||||||
free_notification(n);
|
free_notification(n);
|
||||||
@ -963,6 +972,7 @@ int init_notification(notification * n, int id)
|
|||||||
n->id = ++next_notification_id;
|
n->id = ++next_notification_id;
|
||||||
} else {
|
} else {
|
||||||
close_notification_by_id(id, -1);
|
close_notification_by_id(id, -1);
|
||||||
|
n->id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strlen(n->msg) == 0) {
|
if(strlen(n->msg) == 0) {
|
||||||
@ -1067,10 +1077,10 @@ void init_shortcut(keyboard_shortcut * ks)
|
|||||||
str++;
|
str++;
|
||||||
*str = '\0';
|
*str = '\0';
|
||||||
str++;
|
str++;
|
||||||
strtrim_end(mod);
|
rstrip(mod);
|
||||||
ks->mask = ks->mask | string_to_mask(mod);
|
ks->mask = ks->mask | string_to_mask(mod);
|
||||||
}
|
}
|
||||||
strtrim_end(str);
|
rstrip(str);
|
||||||
|
|
||||||
ks->sym = XStringToKeysym(str);
|
ks->sym = XStringToKeysym(str);
|
||||||
/* find matching keycode for ks->sym */
|
/* find matching keycode for ks->sym */
|
||||||
@ -1079,10 +1089,9 @@ void init_shortcut(keyboard_shortcut * ks)
|
|||||||
|
|
||||||
ks->code = NoSymbol;
|
ks->code = NoSymbol;
|
||||||
|
|
||||||
int level = ks->mask & ShiftMask ? 1 : 0;
|
|
||||||
|
|
||||||
for (int i = min_keysym; i <= max_keysym; i++) {
|
for (int i = min_keysym; i <= max_keysym; i++) {
|
||||||
if (XkbKeycodeToKeysym(dc->dpy, i, 0, level) == ks->sym) {
|
if (XkbKeycodeToKeysym(dc->dpy, i, 0, 0) == ks->sym
|
||||||
|
|| XkbKeycodeToKeysym(dc->dpy, i, 0, 1) == ks->sym) {
|
||||||
ks->code = i;
|
ks->code = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1195,6 +1204,7 @@ int select_screen(XineramaScreenInfo * info, int info_len)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
int x, y;
|
int x, y;
|
||||||
|
assert(f_mode == FOLLOW_MOUSE || f_mode == FOLLOW_KEYBOARD);
|
||||||
Window root = RootWindow(dc->dpy, DefaultScreen(dc->dpy));
|
Window root = RootWindow(dc->dpy, DefaultScreen(dc->dpy));
|
||||||
|
|
||||||
if (f_mode == FOLLOW_MOUSE) {
|
if (f_mode == FOLLOW_MOUSE) {
|
||||||
@ -1239,10 +1249,9 @@ void update_screen_info()
|
|||||||
{
|
{
|
||||||
#ifdef XINERAMA
|
#ifdef XINERAMA
|
||||||
int n;
|
int n;
|
||||||
int screen = scr.scr;
|
|
||||||
XineramaScreenInfo *info;
|
XineramaScreenInfo *info;
|
||||||
if ((info = XineramaQueryScreens(dc->dpy, &n))) {
|
if ((info = XineramaQueryScreens(dc->dpy, &n))) {
|
||||||
screen = select_screen(info, n);
|
int screen = select_screen(info, n);
|
||||||
if (screen >= n) {
|
if (screen >= n) {
|
||||||
/* invalid monitor, fallback to default */
|
/* invalid monitor, fallback to default */
|
||||||
screen = 0;
|
screen = 0;
|
||||||
@ -1296,7 +1305,7 @@ void setup(void)
|
|||||||
DefaultScreen(dc->dpy)),
|
DefaultScreen(dc->dpy)),
|
||||||
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
|
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
|
||||||
transparency = transparency > 100 ? 100 : transparency;
|
transparency = transparency > 100 ? 100 : transparency;
|
||||||
setopacity(dc, win, (unsigned long)((100 - transparency) * (0xffffffff/100)));
|
setopacity(dc, win, (unsigned long)((100 - transparency) * (0xffffffff/100)));
|
||||||
grab_key(&history_ks);
|
grab_key(&history_ks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1477,26 +1486,6 @@ void parse_cmdline(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef STATIC_CONFIG
|
#ifndef STATIC_CONFIG
|
||||||
static int dunst_ini_get_boolean(const char *value)
|
|
||||||
{
|
|
||||||
switch (value[0]) {
|
|
||||||
case 'y':
|
|
||||||
case 'Y':
|
|
||||||
case 't':
|
|
||||||
case 'T':
|
|
||||||
case '1':
|
|
||||||
return True;
|
|
||||||
case 'n':
|
|
||||||
case 'N':
|
|
||||||
case 'f':
|
|
||||||
case 'F':
|
|
||||||
case '0':
|
|
||||||
return False;
|
|
||||||
default:
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static rule_t *dunst_rules_find_or_create(const char *section)
|
static rule_t *dunst_rules_find_or_create(const char *section)
|
||||||
{
|
{
|
||||||
l_node *iter;
|
l_node *iter;
|
||||||
@ -1518,158 +1507,6 @@ static rule_t *dunst_rules_find_or_create(const char *section)
|
|||||||
return rule;
|
return rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *dunst_ini_get_string(const char *value)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
if (value[0] == '"')
|
|
||||||
s = strdup(value + 1);
|
|
||||||
else
|
|
||||||
s = strdup(value);
|
|
||||||
|
|
||||||
if (s[strlen(s) - 1] == '"')
|
|
||||||
s[strlen(s) - 1] = '\0';
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
dunst_ini_handle(void *user_data, const char *section,
|
|
||||||
const char *name, const char *value)
|
|
||||||
{
|
|
||||||
if (strcmp(section, "global") == 0) {
|
|
||||||
if (strcmp(name, "font") == 0)
|
|
||||||
font = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "format") == 0)
|
|
||||||
format = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "sort") == 0)
|
|
||||||
sort = dunst_ini_get_boolean(value);
|
|
||||||
else if (strcmp(name, "indicate_hidden") == 0)
|
|
||||||
indicate_hidden = dunst_ini_get_boolean(value);
|
|
||||||
else if (strcmp(name, "word_wrap") == 0)
|
|
||||||
word_wrap = dunst_ini_get_boolean(value);
|
|
||||||
else if (strcmp(name, "idle_threshold") == 0)
|
|
||||||
idle_threshold = atoi(value);
|
|
||||||
else if (strcmp(name, "monitor") == 0)
|
|
||||||
scr.scr = atoi(value);
|
|
||||||
else if (strcmp(name, "follow") == 0) {
|
|
||||||
char *c = dunst_ini_get_string(value);
|
|
||||||
parse_follow_mode(c);
|
|
||||||
free(c);
|
|
||||||
} else if (strcmp(name, "geometry") == 0)
|
|
||||||
geom = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "line_height") == 0)
|
|
||||||
line_height = atoi(value);
|
|
||||||
else if (strcmp(name, "modifier") == 0) {
|
|
||||||
deprecated_dunstrc_shortcuts = True;
|
|
||||||
char *c = dunst_ini_get_string(value);
|
|
||||||
KeySym mod = string_to_mask(c);
|
|
||||||
free(c);
|
|
||||||
close_ks.mask = mod;
|
|
||||||
close_all_ks.mask = mod;
|
|
||||||
history_ks.mask = mod;
|
|
||||||
} else if (strcmp(name, "key") == 0) {
|
|
||||||
close_ks.str = dunst_ini_get_string(value);
|
|
||||||
} else if (strcmp(name, "all_key") == 0) {
|
|
||||||
close_all_ks.str = dunst_ini_get_string(value);
|
|
||||||
} else if (strcmp(name, "history_key") == 0) {
|
|
||||||
history_ks.str = dunst_ini_get_string(value);
|
|
||||||
} else if (strcmp(name, "bounce_freq") == 0) {
|
|
||||||
bounce_freq = atof(value);
|
|
||||||
} else if (strcmp(name, "alignment") == 0) {
|
|
||||||
if (strcmp(value, "left") == 0)
|
|
||||||
align = left;
|
|
||||||
else if (strcmp(value, "center") == 0)
|
|
||||||
align = center;
|
|
||||||
else if (strcmp(value, "right") == 0)
|
|
||||||
align = right;
|
|
||||||
/* FIXME warning on unknown alignment */
|
|
||||||
} else if (strcmp(name, "show_age_threshold") == 0)
|
|
||||||
show_age_threshold = atoi(value);
|
|
||||||
else if (strcmp(name, "sticky_history") == 0)
|
|
||||||
sticky_history = dunst_ini_get_boolean(value);
|
|
||||||
else if (strcmp(name, "separator_height") == 0)
|
|
||||||
separator_height = atoi(value);
|
|
||||||
else if (strcmp(name, "transparency") == 0)
|
|
||||||
transparency = atoi(value);
|
|
||||||
if (strcmp(name, "separator_color") == 0) {
|
|
||||||
char *str = dunst_ini_get_string(value);
|
|
||||||
if (strcmp(str, "auto") == 0)
|
|
||||||
sep_color = AUTO;
|
|
||||||
else if (strcmp(str, "foreground") == 0)
|
|
||||||
sep_color = FOREGROUND;
|
|
||||||
else
|
|
||||||
fprintf(stderr, "Warning: Unknown separator color\n");
|
|
||||||
free(str);
|
|
||||||
}
|
|
||||||
} else if (strcmp(section, "urgency_low") == 0) {
|
|
||||||
if (strcmp(name, "background") == 0)
|
|
||||||
lowbgcolor = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "foreground") == 0)
|
|
||||||
lowfgcolor = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "timeout") == 0)
|
|
||||||
timeouts[LOW] = atoi(value);
|
|
||||||
|
|
||||||
} else if (strcmp(section, "urgency_normal") == 0) {
|
|
||||||
if (strcmp(name, "background") == 0)
|
|
||||||
normbgcolor = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "foreground") == 0)
|
|
||||||
normfgcolor = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "timeout") == 0)
|
|
||||||
timeouts[NORM] = atoi(value);
|
|
||||||
|
|
||||||
} else if (strcmp(section, "urgency_critical") == 0) {
|
|
||||||
if (strcmp(name, "background") == 0)
|
|
||||||
critbgcolor = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "foreground") == 0)
|
|
||||||
critfgcolor = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "timeout") == 0)
|
|
||||||
timeouts[CRIT] = atoi(value);
|
|
||||||
|
|
||||||
} else if (strcmp(section, "shortcuts") == 0) {
|
|
||||||
if (strcmp(name, "close") == 0)
|
|
||||||
close_ks.str = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "close_all") == 0)
|
|
||||||
close_all_ks.str = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "history") == 0)
|
|
||||||
history_ks.str = dunst_ini_get_string(value);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
rule_t *current_rule = dunst_rules_find_or_create(section);
|
|
||||||
|
|
||||||
if (strcmp(name, "appname") == 0)
|
|
||||||
current_rule->appname = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "summary") == 0)
|
|
||||||
current_rule->summary = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "body") == 0)
|
|
||||||
current_rule->body = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "icon") == 0)
|
|
||||||
current_rule->icon = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "timeout") == 0)
|
|
||||||
current_rule->timeout = atoi(value);
|
|
||||||
else if (strcmp(name, "urgency") == 0) {
|
|
||||||
const char *urg = value;
|
|
||||||
|
|
||||||
if (strcmp(urg, "low") == 0)
|
|
||||||
current_rule->urgency = LOW;
|
|
||||||
else if (strcmp(urg, "normal") == 0)
|
|
||||||
current_rule->urgency = NORM;
|
|
||||||
else if (strcmp(urg, "critical") == 0)
|
|
||||||
current_rule->urgency = CRIT;
|
|
||||||
else
|
|
||||||
fprintf(stderr,
|
|
||||||
"unknown urgency: %s, ignoring\n", urg);
|
|
||||||
} else if (strcmp(name, "foreground") == 0)
|
|
||||||
current_rule->fg = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "background") == 0)
|
|
||||||
current_rule->bg = dunst_ini_get_string(value);
|
|
||||||
else if (strcmp(name, "format") == 0)
|
|
||||||
current_rule->format = dunst_ini_get_string(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse_dunstrc(char *cmdline_config_path)
|
void parse_dunstrc(char *cmdline_config_path)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -1695,15 +1532,136 @@ void parse_dunstrc(char *cmdline_config_path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ini_parse_file(config_file, dunst_ini_handle, NULL) < 0) {
|
load_ini_file(config_file);
|
||||||
puts("dunstrc could not be parsed -> skipping\n");
|
|
||||||
|
font = ini_get_string("global", "font", font);
|
||||||
|
format = ini_get_string("global", "format", format);
|
||||||
|
sort = ini_get_bool("global", "sort", sort);
|
||||||
|
indicate_hidden = ini_get_bool("global", "indicate_hidden", indicate_hidden);
|
||||||
|
word_wrap = ini_get_bool("global", "word_wrap", word_wrap);
|
||||||
|
idle_threshold = ini_get_int("global", "idle_threshold", idle_threshold);
|
||||||
|
monitor = ini_get_int("global", "monitor", monitor);
|
||||||
|
{
|
||||||
|
char *c = ini_get_string("global", "follow", "");
|
||||||
|
if (strlen(c) > 0) {
|
||||||
|
parse_follow_mode(c);
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
geom = ini_get_string("global", "geometry", geom);
|
||||||
|
line_height = ini_get_int("global", "line_height", line_height);
|
||||||
|
{
|
||||||
|
char *c = ini_get_string("global", "modifier", "");
|
||||||
|
if (strlen(c) > 0) {
|
||||||
|
deprecated_dunstrc_shortcuts = True;
|
||||||
|
KeySym mod = string_to_mask(c);
|
||||||
|
close_ks.mask = mod;
|
||||||
|
close_all_ks.mask = mod;
|
||||||
|
close_all_ks.mask = mod;
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close_ks.str = ini_get_string("global", "key", close_ks.str);
|
||||||
|
close_all_ks.str = ini_get_string("global", "key", close_all_ks.str);
|
||||||
|
history_ks.str = ini_get_string("global", "key", history_ks.str);
|
||||||
|
bounce_freq = ini_get_double("global", "bounce_freq", bounce_freq);
|
||||||
|
{
|
||||||
|
char *c = ini_get_string("global", "alignment", "");
|
||||||
|
if (strlen(c) > 0) {
|
||||||
|
if (strcmp(c, "left") == 0)
|
||||||
|
align = left;
|
||||||
|
else if (strcmp(c, "center") == 0)
|
||||||
|
align = center;
|
||||||
|
else if (strcmp(c, "right") == 0)
|
||||||
|
align = right;
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Warning: unknown allignment\n");
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
show_age_threshold = ini_get_int("global", "show_age_threshold", show_age_threshold);
|
||||||
|
sticky_history = ini_get_bool("global", "sticky_history", sticky_history);
|
||||||
|
separator_height = ini_get_int("global", "separator_height", separator_height);
|
||||||
|
transparency = ini_get_int("global", "transparency", transparency);
|
||||||
|
{
|
||||||
|
char *c = ini_get_string("global", "separator_color", "");
|
||||||
|
if (strlen(c) > 0) {
|
||||||
|
if (strcmp(c, "auto") == 0)
|
||||||
|
sep_color = AUTO;
|
||||||
|
else if (strcmp(c, "foreground") == 0)
|
||||||
|
sep_color = FOREGROUND;
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Warning: Unknown separator color\n");
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lowbgcolor = ini_get_string("urgency_low", "background", lowbgcolor);
|
||||||
|
lowfgcolor = ini_get_string("urgency_low", "foreground", lowfgcolor);
|
||||||
|
timeouts[LOW] = ini_get_int("urgency_low", "timeout", timeouts[LOW]);
|
||||||
|
normbgcolor = ini_get_string("urgency_normal", "background", normbgcolor);
|
||||||
|
normfgcolor = ini_get_string("urgency_normal", "foreground", normfgcolor);
|
||||||
|
timeouts[NORM] = ini_get_int("urgency_normal", "timeout", timeouts[NORM]);
|
||||||
|
critbgcolor = ini_get_string("urgency_critical", "background", critbgcolor);
|
||||||
|
critfgcolor = ini_get_string("urgency_critical", "foreground", critfgcolor);
|
||||||
|
timeouts[CRIT] = ini_get_int("urgency_critical", "timeout", timeouts[CRIT]);
|
||||||
|
|
||||||
|
close_ks.str = ini_get_string("shortcuts", "close", close_ks.str);
|
||||||
|
close_all_ks.str = ini_get_string("shortcuts", "close_all", close_all_ks.str);
|
||||||
|
history_ks.str = ini_get_string("shortcuts", "history", history_ks.str);
|
||||||
|
|
||||||
|
|
||||||
|
char *cur_section = NULL;
|
||||||
|
for (;;) {
|
||||||
|
cur_section = next_section(cur_section);
|
||||||
|
if (!cur_section)
|
||||||
|
break;
|
||||||
|
if (strcmp(cur_section, "global") == 0
|
||||||
|
|| strcmp(cur_section, "shortcuts") == 0
|
||||||
|
|| strcmp(cur_section, "urgency_low") == 0
|
||||||
|
|| strcmp(cur_section, "urgency_normal") == 0
|
||||||
|
|| strcmp(cur_section, "urgency_critical") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rule_t *current_rule = dunst_rules_find_or_create(cur_section);
|
||||||
|
current_rule->appname = ini_get_string(
|
||||||
|
cur_section, "appname", current_rule->appname);
|
||||||
|
current_rule->summary = ini_get_string(
|
||||||
|
cur_section, "summary", current_rule->summary);
|
||||||
|
current_rule->body = ini_get_string(
|
||||||
|
cur_section, "body", current_rule->body);
|
||||||
|
current_rule->icon = ini_get_string(
|
||||||
|
cur_section, "icon", current_rule->icon);
|
||||||
|
current_rule->timeout = ini_get_int(
|
||||||
|
cur_section, "timeout", current_rule->timeout);
|
||||||
|
{
|
||||||
|
char *urg = ini_get_string(cur_section, "urgency", "");
|
||||||
|
if (strlen(urg) > 0) {
|
||||||
|
if (strcmp(urg, "low") == 0)
|
||||||
|
current_rule->urgency = LOW;
|
||||||
|
else if (strcmp(urg, "normal") == 0)
|
||||||
|
current_rule->urgency = NORM;
|
||||||
|
else if (strcmp(urg, "critical") == 0)
|
||||||
|
current_rule->urgency = CRIT;
|
||||||
|
else
|
||||||
|
fprintf(stderr,
|
||||||
|
"unknown urgency: %s, ignoring\n", urg);
|
||||||
|
free(urg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_rule->fg = ini_get_string(
|
||||||
|
cur_section, "foreground", current_rule->fg);
|
||||||
|
current_rule->bg = ini_get_string(
|
||||||
|
cur_section, "background", current_rule->bg);
|
||||||
|
current_rule->format = ini_get_string(
|
||||||
|
cur_section, "format", current_rule->format);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(config_file);
|
fclose(config_file);
|
||||||
|
free_ini();
|
||||||
xdgWipeHandle(&xdg);
|
xdgWipeHandle(&xdg);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif /* STATIC_CONFIG */
|
|
||||||
|
|
||||||
char *parse_cmdline_for_config_file(int argc, char *argv[])
|
char *parse_cmdline_for_config_file(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -1718,6 +1676,7 @@ char *parse_cmdline_for_config_file(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif /* STATIC_CONFIG */
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
2
dunst.h
2
dunst.h
@ -33,7 +33,6 @@ typedef struct _screen_info {
|
|||||||
typedef struct _draw_txt {
|
typedef struct _draw_txt {
|
||||||
char *txt;
|
char *txt;
|
||||||
int line_count;
|
int line_count;
|
||||||
int bufsize;
|
|
||||||
} draw_txt;
|
} draw_txt;
|
||||||
|
|
||||||
typedef struct _notification {
|
typedef struct _notification {
|
||||||
@ -54,6 +53,7 @@ typedef struct _notification {
|
|||||||
int dup_count;
|
int dup_count;
|
||||||
ColorSet *colors;
|
ColorSet *colors;
|
||||||
char *color_strings[2];
|
char *color_strings[2];
|
||||||
|
int progress; /* percentage + 1, 0 to hide */
|
||||||
} notification;
|
} notification;
|
||||||
|
|
||||||
typedef struct _notification_buffer {
|
typedef struct _notification_buffer {
|
||||||
|
14
dunst_dbus.c
14
dunst_dbus.c
@ -20,7 +20,7 @@ static void _extract_basic(int type, DBusMessageIter * iter, void *target)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_extract_hint(const char *name, const char *hint_name,
|
_extract_hint(int type, const char *name, const char *hint_name,
|
||||||
DBusMessageIter * hint, void *target)
|
DBusMessageIter * hint, void *target)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ _extract_hint(const char *name, const char *hint_name,
|
|||||||
dbus_message_iter_next(hint);
|
dbus_message_iter_next(hint);
|
||||||
dbus_message_iter_recurse(hint, &hint_value);
|
dbus_message_iter_recurse(hint, &hint_value);
|
||||||
do {
|
do {
|
||||||
dbus_message_iter_get_basic(&hint_value, target);
|
_extract_basic(type, &hint_value, target);
|
||||||
} while (dbus_message_iter_next(hint));
|
} while (dbus_message_iter_next(hint));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,6 +296,7 @@ void notify(DBusMessage * dmsg)
|
|||||||
const char *fgcolor = NULL;
|
const char *fgcolor = NULL;
|
||||||
const char *bgcolor = NULL;
|
const char *bgcolor = NULL;
|
||||||
int urgency = 1;
|
int urgency = 1;
|
||||||
|
int progress = -1;
|
||||||
notification *n = malloc(sizeof(notification));
|
notification *n = malloc(sizeof(notification));
|
||||||
dbus_uint32_t replaces_id = 0;
|
dbus_uint32_t replaces_id = 0;
|
||||||
dbus_int32_t expires = -1;
|
dbus_int32_t expires = -1;
|
||||||
@ -335,9 +336,11 @@ void notify(DBusMessage * dmsg)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dbus_message_iter_get_basic(&hint, &hint_name);
|
dbus_message_iter_get_basic(&hint, &hint_name);
|
||||||
_extract_hint("urgency", hint_name, &hint, &urgency);
|
_extract_hint(DBUS_TYPE_BYTE, "urgency", hint_name, &hint, &urgency);
|
||||||
_extract_hint("fgcolor", hint_name, &hint, &fgcolor);
|
_extract_hint(DBUS_TYPE_STRING, "fgcolor", hint_name, &hint, &fgcolor);
|
||||||
_extract_hint("bgcolor", hint_name, &hint, &bgcolor);
|
_extract_hint(DBUS_TYPE_STRING, "bgcolor", hint_name, &hint, &bgcolor);
|
||||||
|
_extract_hint(DBUS_TYPE_INT32, "value", hint_name, &hint, &progress);
|
||||||
|
if (!progress) _extract_hint(DBUS_TYPE_UINT32, "value", hint_name, &hint, &progress);
|
||||||
dbus_message_iter_next(&hint);
|
dbus_message_iter_next(&hint);
|
||||||
}
|
}
|
||||||
dbus_message_iter_next(&hints);
|
dbus_message_iter_next(&hints);
|
||||||
@ -355,6 +358,7 @@ void notify(DBusMessage * dmsg)
|
|||||||
n->body = body != NULL ? strdup(body) : "";
|
n->body = body != NULL ? strdup(body) : "";
|
||||||
n->icon = icon != NULL ? strdup(icon) : "";
|
n->icon = icon != NULL ? strdup(icon) : "";
|
||||||
n->timeout = expires;
|
n->timeout = expires;
|
||||||
|
n->progress = (progress < 0 || progress > 100) ? 0 : progress+1;
|
||||||
n->urgency = urgency;
|
n->urgency = urgency;
|
||||||
n->dbus_client = strdup(dbus_message_get_sender(dmsg));
|
n->dbus_client = strdup(dbus_message_get_sender(dmsg));
|
||||||
for (i = 0; i < ColLast; i++) {
|
for (i = 0; i < ColLast; i++) {
|
||||||
|
1
dunstrc
1
dunstrc
@ -7,6 +7,7 @@
|
|||||||
# %b body
|
# %b body
|
||||||
# %i iconname (including its path)
|
# %i iconname (including its path)
|
||||||
# %I iconname (without its path)
|
# %I iconname (without its path)
|
||||||
|
# %p progress value if set ([ 0%] to [100%]) or nothing
|
||||||
format = "%s %b"
|
format = "%s %b"
|
||||||
|
|
||||||
# Sort messages by urgency
|
# Sort messages by urgency
|
||||||
|
176
ini.c
176
ini.c
@ -1,176 +0,0 @@
|
|||||||
/* inih -- simple .INI file parser
|
|
||||||
|
|
||||||
inih is released under the New BSD license. Go to the project
|
|
||||||
home page for more info:
|
|
||||||
|
|
||||||
The "inih" library is distributed under the New BSD license:
|
|
||||||
|
|
||||||
Copyright (c) 2009, Brush Technology
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of Brush Technology nor the names of its contributors
|
|
||||||
may be used to endorse or promote products derived from this software
|
|
||||||
without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY
|
|
||||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY
|
|
||||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
http://code.google.com/p/inih/
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "ini.h"
|
|
||||||
|
|
||||||
#define MAX_LINE 200
|
|
||||||
#define MAX_SECTION 50
|
|
||||||
#define MAX_NAME 50
|
|
||||||
|
|
||||||
/* Strip whitespace chars off end of given string, in place. Return s. */
|
|
||||||
static char* rstrip(char* s)
|
|
||||||
{
|
|
||||||
char* p = s + strlen(s);
|
|
||||||
while (p > s && isspace(*--p))
|
|
||||||
*p = '\0';
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return pointer to first non-whitespace char in given string. */
|
|
||||||
static char* lskip(const char* s)
|
|
||||||
{
|
|
||||||
while (*s && isspace(*s))
|
|
||||||
s++;
|
|
||||||
return (char*)s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return pointer to first char c or ';' comment in given string, or pointer to
|
|
||||||
null at end of string if neither found. ';' must be prefixed by a whitespace
|
|
||||||
character to register as a comment. */
|
|
||||||
static char* find_char_or_comment(const char* s, char c)
|
|
||||||
{
|
|
||||||
int was_whitespace = 0;
|
|
||||||
while (*s && *s != c && !(was_whitespace && *s == ';')) {
|
|
||||||
was_whitespace = isspace(*s);
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
return (char*)s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
|
|
||||||
static char* strncpy0(char* dest, const char* src, size_t size)
|
|
||||||
{
|
|
||||||
strncpy(dest, src, size);
|
|
||||||
dest[size - 1] = '\0';
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See documentation in header file. */
|
|
||||||
int ini_parse_file(FILE* file,
|
|
||||||
int (*handler)(void*, const char*, const char*,
|
|
||||||
const char*),
|
|
||||||
void* user)
|
|
||||||
{
|
|
||||||
/* Uses a fair bit of stack (use heap instead if you need to) */
|
|
||||||
char line[MAX_LINE];
|
|
||||||
char section[MAX_SECTION] = "";
|
|
||||||
char prev_name[MAX_NAME] = "";
|
|
||||||
|
|
||||||
char* start;
|
|
||||||
char* end;
|
|
||||||
char* name;
|
|
||||||
char* value;
|
|
||||||
int lineno = 0;
|
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
/* Scan through file line by line */
|
|
||||||
while (fgets(line, sizeof(line), file) != NULL) {
|
|
||||||
lineno++;
|
|
||||||
start = lskip(rstrip(line));
|
|
||||||
|
|
||||||
if (*start == ';' || *start == '#') {
|
|
||||||
/* Per Python ConfigParser, allow '#' comments at start of line */
|
|
||||||
}
|
|
||||||
#if INI_ALLOW_MULTILINE
|
|
||||||
else if (*prev_name && *start && start > line) {
|
|
||||||
/* Non-black line with leading whitespace, treat as continuation
|
|
||||||
of previous name's value (as per Python ConfigParser). */
|
|
||||||
if (!handler(user, section, prev_name, start) && !error)
|
|
||||||
error = lineno;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (*start == '[') {
|
|
||||||
/* A "[section]" line */
|
|
||||||
end = find_char_or_comment(start + 1, ']');
|
|
||||||
if (*end == ']') {
|
|
||||||
*end = '\0';
|
|
||||||
strncpy0(section, start + 1, sizeof(section));
|
|
||||||
*prev_name = '\0';
|
|
||||||
}
|
|
||||||
else if (!error) {
|
|
||||||
/* No ']' found on section line */
|
|
||||||
error = lineno;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*start && *start != ';') {
|
|
||||||
/* Not a comment, must be a name[=:]value pair */
|
|
||||||
end = find_char_or_comment(start, '=');
|
|
||||||
if (*end != '=') {
|
|
||||||
end = find_char_or_comment(start, ':');
|
|
||||||
}
|
|
||||||
if (*end == '=' || *end == ':') {
|
|
||||||
*end = '\0';
|
|
||||||
name = rstrip(start);
|
|
||||||
value = lskip(end + 1);
|
|
||||||
end = find_char_or_comment(value, '\0');
|
|
||||||
if (*end == ';')
|
|
||||||
*end = '\0';
|
|
||||||
rstrip(value);
|
|
||||||
|
|
||||||
/* Valid name[=:]value pair found, call handler */
|
|
||||||
strncpy0(prev_name, name, sizeof(prev_name));
|
|
||||||
if (!handler(user, section, name, value) && !error)
|
|
||||||
error = lineno;
|
|
||||||
}
|
|
||||||
else if (!error) {
|
|
||||||
/* No '=' or ':' found on name[=:]value line */
|
|
||||||
error = lineno;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See documentation in header file. */
|
|
||||||
int ini_parse(const char* filename,
|
|
||||||
int (*handler)(void*, const char*, const char*, const char*),
|
|
||||||
void* user)
|
|
||||||
{
|
|
||||||
FILE* file;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
file = fopen(filename, "r");
|
|
||||||
if (!file)
|
|
||||||
return -1;
|
|
||||||
error = ini_parse_file(file, handler, user);
|
|
||||||
fclose(file);
|
|
||||||
return error;
|
|
||||||
}
|
|
83
ini.h
83
ini.h
@ -1,83 +0,0 @@
|
|||||||
/* inih -- simple .INI file parser
|
|
||||||
|
|
||||||
inih is released under the New BSD license. Go to the project
|
|
||||||
home page for more info:
|
|
||||||
|
|
||||||
The "inih" library is distributed under the New BSD license:
|
|
||||||
|
|
||||||
Copyright (c) 2009, Brush Technology
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of Brush Technology nor the names of its contributors
|
|
||||||
may be used to endorse or promote products derived from this software
|
|
||||||
without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY
|
|
||||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY
|
|
||||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
http://code.google.com/p/inih/
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __INI_H__
|
|
||||||
#define __INI_H__
|
|
||||||
|
|
||||||
/* Make this header file easier to include in C++ code */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/* Parse given INI-style file. May have [section]s, name=value pairs
|
|
||||||
(whitespace stripped), and comments starting with ';' (semicolon). Section
|
|
||||||
is "" if name=value pair parsed before any section heading. name:value
|
|
||||||
pairs are also supported as a concession to Python's ConfigParser.
|
|
||||||
|
|
||||||
For each name=value pair parsed, call handler function with given user
|
|
||||||
pointer as well as section, name, and value (data only valid for duration
|
|
||||||
of handler call). Handler should return nonzero on success, zero on error.
|
|
||||||
|
|
||||||
Returns 0 on success, line number of first error on parse error (doesn't
|
|
||||||
stop on first error), or -1 on file open error.
|
|
||||||
*/
|
|
||||||
int ini_parse(const char* filename,
|
|
||||||
int (*handler)(void* user, const char* section,
|
|
||||||
const char* name, const char* value),
|
|
||||||
void* user);
|
|
||||||
|
|
||||||
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
|
|
||||||
close the file when it's finished -- the caller must do that. */
|
|
||||||
int ini_parse_file(FILE* file,
|
|
||||||
int (*handler)(void* user, const char* section,
|
|
||||||
const char* name, const char* value),
|
|
||||||
void* user);
|
|
||||||
|
|
||||||
/* Nonzero to allow multi-line value parsing, in the style of Python's
|
|
||||||
ConfigParser. If allowed, ini_parse() will call the handler with the same
|
|
||||||
name for each subsequent line parsed. */
|
|
||||||
#ifndef INI_ALLOW_MULTILINE
|
|
||||||
#define INI_ALLOW_MULTILINE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __INI_H__ */
|
|
258
options.c
Normal file
258
options.c
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
/* copyright 2012 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
typedef struct _entry_t {
|
||||||
|
char *key;
|
||||||
|
char *value;
|
||||||
|
} entry_t;
|
||||||
|
|
||||||
|
typedef struct _section_t {
|
||||||
|
char *name;
|
||||||
|
int entry_count;
|
||||||
|
entry_t *entries;
|
||||||
|
} section_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int section_count;
|
||||||
|
static section_t *sections;
|
||||||
|
|
||||||
|
static section_t *new_section(char *name);
|
||||||
|
static section_t *get_section(char *name);
|
||||||
|
static void add_entry(char *section_name, char *key, char *value);
|
||||||
|
static char *get_value(char *section, char *key);
|
||||||
|
static char *clean_value(char *value);
|
||||||
|
|
||||||
|
section_t *new_section(char *name)
|
||||||
|
{
|
||||||
|
section_count++;
|
||||||
|
sections = realloc(sections, sizeof(section_t) *section_count);
|
||||||
|
sections[section_count - 1].name = strdup(name);
|
||||||
|
sections[section_count - 1].entries = NULL;
|
||||||
|
sections[section_count - 1].entry_count = 0;
|
||||||
|
return §ions[section_count -1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_ini(void)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < section_count; i++) {
|
||||||
|
for (int j = 0; j < sections[i].entry_count; j++) {
|
||||||
|
free(sections[i].entries[j].key);
|
||||||
|
free(sections[i].entries[j].value);
|
||||||
|
}
|
||||||
|
free(sections[i].entries);
|
||||||
|
free(sections[i].name);
|
||||||
|
}
|
||||||
|
free(sections);
|
||||||
|
}
|
||||||
|
|
||||||
|
section_t *get_section(char *name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < section_count; i++) {
|
||||||
|
if (strcmp(sections[i].name, name) == 0)
|
||||||
|
return §ions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_entry(char *section_name, char *key, char *value)
|
||||||
|
{
|
||||||
|
section_t *s = get_section(section_name);
|
||||||
|
if (s == NULL) {
|
||||||
|
s = new_section(section_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->entry_count++;
|
||||||
|
int len = s->entry_count;
|
||||||
|
s->entries = realloc(s->entries, sizeof(entry_t) * len);
|
||||||
|
s->entries[s->entry_count - 1].key = strdup(key);
|
||||||
|
s->entries[s->entry_count - 1].value = clean_value(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_value(char *section, char *key)
|
||||||
|
{
|
||||||
|
section_t *s = get_section(section);
|
||||||
|
if (!s) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < s->entry_count; i++) {
|
||||||
|
if (strcmp(s->entries[i].key, key) == 0) {
|
||||||
|
return s->entries[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ini_get_string(char *section, char *key, const char *def)
|
||||||
|
{
|
||||||
|
char *value = get_value(section, key);
|
||||||
|
if (value == NULL)
|
||||||
|
return def;
|
||||||
|
else
|
||||||
|
return strdup(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ini_get_int(char *section, char *key, int def)
|
||||||
|
{
|
||||||
|
char *value = get_value(section, key);
|
||||||
|
if (value == NULL)
|
||||||
|
return def;
|
||||||
|
else
|
||||||
|
return atoi(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
double ini_get_double(char *section, char *key, int def)
|
||||||
|
{
|
||||||
|
char *value = get_value(section, key);
|
||||||
|
if (value == NULL)
|
||||||
|
return def;
|
||||||
|
else
|
||||||
|
return atof(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *next_section(char *section)
|
||||||
|
{
|
||||||
|
if (section_count == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (section == NULL) {
|
||||||
|
return sections[0].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < section_count; i++) {
|
||||||
|
if (strcmp(section, sections[i].name) == 0) {
|
||||||
|
if (i + 1 >= section_count)
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
|
return sections[i+1].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ini_get_bool(char *section, char *key, int def)
|
||||||
|
{
|
||||||
|
char *value = get_value(section, key);
|
||||||
|
if (value == NULL)
|
||||||
|
return def;
|
||||||
|
else {
|
||||||
|
switch (value[0]) {
|
||||||
|
case 'y':
|
||||||
|
case 'Y':
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
case '1':
|
||||||
|
return true;
|
||||||
|
case 'n':
|
||||||
|
case 'N':
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
case '0':
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *clean_value(char *value)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if (value[0] == '"')
|
||||||
|
s = strdup(value + 1);
|
||||||
|
else
|
||||||
|
s = strdup(value);
|
||||||
|
|
||||||
|
if (s[strlen(s) - 1] == '"')
|
||||||
|
s[strlen(s) - 1] = '\0';
|
||||||
|
|
||||||
|
return s;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_ini_file(FILE *fp)
|
||||||
|
{
|
||||||
|
char line[BUFSIZ];
|
||||||
|
|
||||||
|
int line_num = 0;
|
||||||
|
char *current_section = NULL;
|
||||||
|
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||||
|
line_num++;
|
||||||
|
|
||||||
|
char *start = lskip(rstrip(line));
|
||||||
|
|
||||||
|
if (*start == ';' || *start == '#' || strlen(start) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (*start == '[') {
|
||||||
|
char *end = strstr(start + 1, "]");
|
||||||
|
if (!end) {
|
||||||
|
printf("Warning: invalid config file at line %d\n", line_num);
|
||||||
|
printf("Missing ']'\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*end = '\0';
|
||||||
|
|
||||||
|
if (current_section)
|
||||||
|
free(current_section);
|
||||||
|
current_section = (strdup(start+1));
|
||||||
|
new_section(current_section);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *equal = strstr(start + 1, "=");
|
||||||
|
if (!equal) {
|
||||||
|
printf("Warning: invalid config file at line %d\n", line_num);
|
||||||
|
printf("Missing '='\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*equal = '\0';
|
||||||
|
char *key = rstrip(start);
|
||||||
|
char *value = lskip(equal+1);
|
||||||
|
|
||||||
|
char *quote = strstr(value, "\"");
|
||||||
|
if (quote) {
|
||||||
|
char *closing_quote = strstr(quote + 1, "\"");
|
||||||
|
if (!closing_quote) {
|
||||||
|
printf("Warning: invalid config file at line %d\n", line_num);
|
||||||
|
printf("Missing '\"'\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
closing_quote = '\0';
|
||||||
|
} else {
|
||||||
|
char *comment = strstr(value, "#");
|
||||||
|
if (!comment)
|
||||||
|
comment = strstr(value, ";");
|
||||||
|
if (comment)
|
||||||
|
comment = '\0';
|
||||||
|
}
|
||||||
|
value = rstrip(value);
|
||||||
|
|
||||||
|
if (!current_section) {
|
||||||
|
printf("Warning: invalid config file at line: %d\n", line_num);
|
||||||
|
printf("Key value pair without a section\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_entry(current_section, key, value);
|
||||||
|
}
|
||||||
|
if (current_section)
|
||||||
|
free(current_section);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* vim: set ts=8 sw=8 tw=0: */
|
20
options.h
Normal file
20
options.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/* copyright 2012 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
int load_ini_file(FILE *);
|
||||||
|
char *ini_get_string(char *section, char *key, const char *def);
|
||||||
|
int ini_get_int(char *section, char *key, int def);
|
||||||
|
double ini_get_double(char *section, char *key, int def);
|
||||||
|
int ini_get_bool(char *section, char *key, int def);
|
||||||
|
void free_ini(void);
|
||||||
|
|
||||||
|
/* returns the next known section.
|
||||||
|
* if section == NULL returns first section.
|
||||||
|
* returns NULL if no more sections are available
|
||||||
|
*/
|
||||||
|
char *next_section(char *section);
|
||||||
|
|
||||||
|
/* vim: set ts=8 sw=8 tw=0: */
|
9
utils.c
9
utils.c
@ -7,7 +7,7 @@
|
|||||||
#include "dunst.h"
|
#include "dunst.h"
|
||||||
|
|
||||||
|
|
||||||
void strtrim_end(char *str)
|
char *rstrip(char *str)
|
||||||
{
|
{
|
||||||
char *end;
|
char *end;
|
||||||
end = str + strlen(str) - 1;
|
end = str + strlen(str) - 1;
|
||||||
@ -15,6 +15,13 @@ void strtrim_end(char *str)
|
|||||||
*end = '\0';
|
*end = '\0';
|
||||||
end--;
|
end--;
|
||||||
}
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *lskip(char *s)
|
||||||
|
{
|
||||||
|
for(; *s && isspace(*s); s++);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *string_replace(const char *needle, const char *replacement,
|
char *string_replace(const char *needle, const char *replacement,
|
||||||
|
3
utils.h
3
utils.h
@ -1,7 +1,8 @@
|
|||||||
#ifndef UTIL_H
|
#ifndef UTIL_H
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
/* remove spaces before and after str */
|
/* remove spaces before and after str */
|
||||||
void strtrim_end(char *str);
|
char *rstrip(char *str);
|
||||||
|
char *lskip(char *str);
|
||||||
|
|
||||||
/* replace needle with replacement in haystack */
|
/* replace needle with replacement in haystack */
|
||||||
char *string_replace(const char *needle, const char *replacement,
|
char *string_replace(const char *needle, const char *replacement,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user