25#define RULE_APPLY2(nprop, rprop, defval) \
26 if (r->rprop != (defval)) { \
27 if (save && n->original->rprop == (defval)) \
28 n->original->rprop = n->nprop; \
29 n->nprop = r->rprop; \
32#define RULE_APPLY(prop, defval) RULE_APPLY2(prop, prop, defval)
40 if (save) notification_keep_original(n);
42 RULE_APPLY2(dbus_timeout, override_dbus_timeout, -1);
43 RULE_APPLY2(transient, set_transient, -1);
45 RULE_APPLY(timeout, -1);
47 RULE_APPLY(fullscreen,
FS_NULL);
48 RULE_APPLY(history_ignore, -1);
49 RULE_APPLY(skip_display, -1);
50 RULE_APPLY(word_wrap, -1);
51 RULE_APPLY(ellipsize, -1);
52 RULE_APPLY(alignment, -1);
53 RULE_APPLY(hide_text, -1);
54 RULE_APPLY(progress_bar_alignment, -1);
55 RULE_APPLY(min_icon_size, -1);
56 RULE_APPLY(max_icon_size, -1);
57 RULE_APPLY(markup, MARKUP_NULL);
58 RULE_APPLY(icon_position, -1);
59 RULE_APPLY(override_pause_level, -1);
61 if (COLOR_VALID(r->fg)) {
62 if (save && !COLOR_VALID(n->original->fg)) n->original->fg = n->colors.fg;
65 if (COLOR_VALID(r->bg)) {
66 if (save && !COLOR_VALID(n->original->bg)) n->original->bg = n->colors.bg;
69 if (r->highlight != NULL) {
70 if (save && n->original->highlight == NULL) {
71 n->original->highlight = gradient_acquire(n->colors.highlight);
73 gradient_release(n->colors.highlight);
74 n->colors.highlight = gradient_acquire(r->highlight);
76 if (COLOR_VALID(r->fc)) {
77 if (save && !COLOR_VALID(n->original->fc)) n->original->fc = n->colors.frame;
78 n->colors.frame = r->fc;
81 if (save && n->original->action_name == NULL)
88 if (r->set_category) {
89 if (save && n->original->set_category == NULL)
90 n->original->set_category = n->category;
94 n->category = g_strdup(r->set_category);
96 if (r->default_icon) {
97 if (save && n->original->default_icon == NULL)
104 if (r->set_stack_tag) {
105 if (save && n->original->set_stack_tag == NULL)
106 n->original->set_stack_tag = n->
stack_tag;
110 n->
stack_tag = g_strdup(r->set_stack_tag);
113 if (save && n->original->new_icon == NULL)
114 n->original->new_icon = g_strdup(n->
iconname);
123 if (r->format != NULL) {
124 if (save && n->original->format == NULL)
125 n->original->format = n->format;
129 n->format = g_strdup(r->format);
132 if (save && n->original->script == NULL)
133 n->original->script = n->script_count > 0
134 ? g_strdup(n->scripts[0])
135 : g_strdup(r->script);
137 n->scripts = g_renew(
char *, n->scripts, n->script_count + 2);
138 n->scripts[n->script_count] = g_strdup(r->script);
139 n->scripts[n->script_count + 1] = NULL;
144void rule_print(
const struct rule *r)
147 printf(
"\tname: '%s'\n",
STR_NN(r->name));
148 printf(
"\tenabled: %d\n", r->enabled);
151 if (r->appname != NULL) printf(
"\tappname: '%s'\n", r->appname);
152 if (r->summary != NULL) printf(
"\tsummary: '%s'\n", r->summary);
153 if (r->body != NULL) printf(
"\tbody: '%s'\n", r->body);
154 if (r->icon != NULL) printf(
"\ticon: '%s'\n", r->icon);
155 if (r->category != NULL) printf(
"\tcategory: '%s'\n", r->category);
156 if (r->msg_urgency !=
URG_NONE) printf(
"\tmsg_urgency: '%s'\n", notification_urgency_to_string(r->msg_urgency));
157 if (r->stack_tag != NULL) printf(
"\tstack_tag: '%s'\n", r->stack_tag);
158 if (r->desktop_entry != NULL) printf(
"\tdesktop_entry: '%s'\n", r->desktop_entry);
159 if (r->match_dbus_timeout != -1) printf(
"\tmatch_dbus_timeout: %"G_GINT64_FORMAT
"\n", r->match_dbus_timeout);
160 if (r->match_transient != -1) printf(
"\tmatch_transient: %d\n", r->match_transient);
163 if (r->timeout != -1) printf(
"\ttimeout: %"G_GINT64_FORMAT
"\n", r->timeout);
164 if (r->override_dbus_timeout != -1) printf(
"\toverride_dbus_timeout: %"G_GINT64_FORMAT
"\n", r->override_dbus_timeout);
165 if (r->markup != -1) printf(
"\tmarkup: %d\n", r->markup);
166 if (r->action_name != NULL) printf(
"\taction_name: '%s'\n", r->action_name);
167 if (r->urgency !=
URG_NONE) printf(
"\turgency: '%s'\n", notification_urgency_to_string(r->urgency));
168 if (r->history_ignore != -1) printf(
"\thistory_ignore: %d\n", r->history_ignore);
169 if (r->set_transient != -1) printf(
"\tset_transient: %d\n", r->set_transient);
170 if (r->skip_display != -1) printf(
"\tskip_display: %d\n", r->skip_display);
171 if (r->word_wrap != -1) printf(
"\tword_wrap: %d\n", r->word_wrap);
172 if (r->ellipsize != -1) printf(
"\tellipsize: %d\n", r->ellipsize);
173 if (r->alignment != -1) printf(
"\talignment: %d\n", r->alignment);
174 if (r->hide_text != -1) printf(
"\thide_text: %d\n", r->hide_text);
175 if (r->icon_position != -1) printf(
"\ticon_position: %d\n", r->icon_position);
176 if (r->min_icon_size != -1) printf(
"\tmin_icon_size: %d\n", r->min_icon_size);
177 if (r->max_icon_size != -1) printf(
"\tmax_icon_size: %d\n", r->max_icon_size);
178 if (r->override_pause_level != -1) printf(
"\toverride_pause_level: %d\n", r->override_pause_level);
179 if (r->new_icon != NULL) printf(
"\tnew_icon: '%s'\n", r->new_icon);
180 if (r->default_icon != NULL) printf(
"\tdefault_icon: '%s'\n", r->default_icon);
183 if (COLOR_VALID(r->fg)) printf(
"\tfg: %s\n",
color_to_string(r->fg, buf));
184 if (COLOR_VALID(r->bg)) printf(
"\tbg: %s\n",
color_to_string(r->bg, buf));
185 if (COLOR_VALID(r->fc)) printf(
"\tframe: %s\n",
color_to_string(r->fc, buf));
187 char *grad = gradient_to_string(r->highlight);
188 printf(
"\thighlight: %s\n",
STR_NN(grad));
191 if (r->set_category != NULL) printf(
"\tset_category: '%s'\n", r->set_category);
192 if (r->format != NULL) printf(
"\tformat: '%s'\n", r->format);
193 if (r->script != NULL) printf(
"\tscript: '%s'\n", r->script);
195 if (r->progress_bar_alignment != -1) printf(
"\tprogress_bar_alignment: %d\n", r->progress_bar_alignment);
196 if (r->set_stack_tag != NULL) printf(
"\tset_stack_tag: %s\n", r->set_stack_tag);
205 for (GSList *iter = rules; iter; iter = iter->next) {
206 struct rule *r = iter->data;
207 if (rule_matches_notification(r, n)) {
208 rule_apply(r, n,
true);
213bool rule_apply_special_filters(
struct rule *r,
const char *name) {
217 if (strcmp(name,
"global") == 0) {
221 if (strcmp(name,
"urgency_low") == 0) {
225 if (strcmp(name,
"urgency_normal") == 0) {
229 if (strcmp(name,
"urgency_critical") == 0) {
239 struct rule *r = g_malloc0(
sizeof(
struct rule));
241 rules = g_slist_insert(rules, r, -1);
242 r->name = g_strdup(name);
244 bool success = rule_apply_special_filters(r, name);
246 LOG_M(
"Could not apply special filters for section %s", name);
252void rule_free(
struct rule *r)
254 if (r == NULL || r == &empty_rule)
263 g_free(r->stack_tag);
264 g_free(r->desktop_entry);
266 g_free(r->action_name);
268 g_free(r->default_icon);
269 gradient_release(r->highlight);
271 g_free(r->set_category);
274 g_free(r->set_stack_tag);
280static inline bool rule_field_matches_string(
const char *value,
const char *pattern)
292 int err = regcomp(®ex, pattern, REG_NEWLINE | REG_EXTENDED | REG_NOSUB);
294 size_t err_size = regerror(err, ®ex, NULL, 0);
295 char *err_buf = g_malloc(err_size);
296 regerror(err, ®ex, err_buf, err_size);
297 LOG_W(
"%s: \"%s\"", err_buf, pattern);
303 if (regexec(®ex, value, 0, NULL, 0))
311 return !pattern || (value && !fnmatch(pattern, value, 0));
321 && (r->msg_urgency ==
URG_NONE || r->msg_urgency == n->urgency)
322 && (r->match_dbus_timeout < 0 || (r->match_dbus_timeout == n->
dbus_timeout))
323 && (r->match_transient == -1 || (r->match_transient == n->
transient))
324 && rule_field_matches_string(n->appname, r->appname)
325 && rule_field_matches_string(n->
desktop_entry, r->desktop_entry)
326 && rule_field_matches_string(n->summary, r->summary)
327 && rule_field_matches_string(n->body, r->body)
328 && rule_field_matches_string(n->
iconname, r->icon)
329 && rule_field_matches_string(n->category, r->category)
330 && rule_field_matches_string(n->
stack_tag, r->stack_tag);
337 for (GSList *iter = rules; iter; iter = iter->next) {
338 struct rule *r = iter->data;
339 if (r->name &&
STR_EQ(r->name, name))
349 const size_t first_action = offsetof(
struct rule, timeout);
350 const size_t last_action = offsetof(
struct rule, set_stack_tag);
351 return (offset >= first_action) && (offset <= last_action);
358 const size_t first_filter = offsetof(
struct rule, appname);
char * color_to_string(struct color c, char buf[10])
Stringify a color struct to a RRGGBBAA string.
Logging subsystem and helpers.
void notification_icon_replace_path(struct notification *n, const char *new_icon)
Replace the current notification's icon with the icon specified by path.
const char * enum_to_string_fullscreen(enum behavior_fullscreen in)
Return the string representation for fullscreen behavior.
urgency
Representing the urgencies according to the notification spec.
@ URG_NONE
Urgency not set (invalid)
@ URG_NORM
Normal urgency.
@ URG_CRIT
Critical urgency.
struct rule * get_rule(const char *name)
Check if a rule exists with that name.
struct rule * rule_new(const char *name)
Allocate a new rule with given name.
bool rule_offset_is_modifying(const size_t offset)
see rules.h
bool rule_offset_is_filter(const size_t offset)
see rules.h
Rules managment and helpers.
List of all the valid settings and values.
char * stack_tag
stack notifications by tag
bool receiving_raw_icon
Still waiting for raw icon to be received.
char * desktop_entry
The desktop entry hint sent via every GApplication.
char * iconname
plain icon information (may be a path or just a name) as recieved from dbus.
bool transient
timeout albeit user is idle
char * default_icon_name
The icon that is used when no other icon is available.
char * default_action_name
The name of the action to be invoked on do_action.
gint64 dbus_timeout
time to display (in milliseconds) (set by dbus)
bool is_deprecated_section(const char *s)
This function tells if a section is deprecated.
bool is_special_section(const char *s)
Some sections are handled differently in dunst.
String, time and other various helpers.
#define STR_EMPTY(s)
Test if a string is NULL or empty.
#define STR_EQ(a, b)
Test if string a and b contain the same chars.
#define STR_NN(s)
Get a non null string from a possibly null one.