Merge pull request #552 from Gravemind/x-canonical-private-synchronous
Implement x-canonical-private-synchronous hint
This commit is contained in:
commit
27c6a1682d
@ -611,9 +611,9 @@ matched.
|
||||
=item B<filtering>
|
||||
|
||||
Notifications can be matched for any of the following attributes: appname,
|
||||
summary, body, icon, category, match_transient and msg_urgency where each is
|
||||
the respective notification attribute to be matched and 'msg_urgency' is the
|
||||
urgency of the notification, it is named so to not conflict with trying to
|
||||
summary, body, icon, category, match_transient, msg_urgency, and stack_tag where
|
||||
each is the respective notification attribute to be matched and 'msg_urgency' is
|
||||
the urgency of the notification, it is named so to not conflict with trying to
|
||||
modify the urgency.
|
||||
|
||||
To define a matching rule simply assign the specified value to the value that
|
||||
@ -630,9 +630,9 @@ Shell-like globing is supported.
|
||||
=item B<modifying>
|
||||
|
||||
The following attributes can be overridden: timeout, urgency, foreground,
|
||||
background, frame_color, new_icon, set_transient, format, fullscreen where,
|
||||
as with the filtering attributes, each one corresponds to the respective
|
||||
notification attribute to be modified.
|
||||
background, frame_color, new_icon, set_transient, format, fullscreen,
|
||||
set_stack_tag where, as with the filtering attributes, each one corresponds to
|
||||
the respective notification attribute to be modified.
|
||||
|
||||
As with filtering, to make a rule modify an attribute simply assign it in the
|
||||
rule definition.
|
||||
@ -640,6 +640,11 @@ rule definition.
|
||||
If the format is set to an empty string, the notification will not be
|
||||
suppressed.
|
||||
|
||||
Notifications with the same non-empty stack_tag value will be stacked
|
||||
together. The default stack_stag value is set from the string hints
|
||||
"synchronous", "private-synchronous", "x-canonical-private-synchronous", and
|
||||
"x-dunst-stack-tag".
|
||||
|
||||
=back
|
||||
|
||||
=head2 SCRIPTING
|
||||
|
11
dunstrc
11
dunstrc
@ -147,10 +147,10 @@
|
||||
# Ignore newlines '\n' in notifications.
|
||||
ignore_newline = no
|
||||
|
||||
# Merge multiple notifications with the same content
|
||||
# Stack together notifications with the same content
|
||||
stack_duplicates = true
|
||||
|
||||
# Hide the count of merged notifications with the same content
|
||||
# Hide the count of stacked notifications with the same content
|
||||
hide_duplicate_count = false
|
||||
|
||||
# Display indicators for URLs (U) and actions (A).
|
||||
@ -299,7 +299,8 @@
|
||||
# override settings for certain messages.
|
||||
# Messages can be matched by "appname", "summary", "body", "icon", "category",
|
||||
# "msg_urgency" and you can override the "timeout", "urgency", "foreground",
|
||||
# "background", "frame_color", "new_icon" and "format", "fullscreen".
|
||||
# "background", "frame_color", "new_icon" and "format", "fullscreen",
|
||||
# "stack_tag".
|
||||
# Shell-like globbing will get expanded.
|
||||
#
|
||||
# SCRIPTING
|
||||
@ -365,4 +366,8 @@
|
||||
# summary = *twitter.com*
|
||||
# urgency = normal
|
||||
#
|
||||
#[stack-volumes]
|
||||
# appname = "some_volume_notifiers"
|
||||
# set_stack_tag = "volume"
|
||||
#
|
||||
# vim: ft=cfg
|
||||
|
24
src/dbus.c
24
src/dbus.c
@ -65,6 +65,13 @@ static const char *introspection_xml =
|
||||
" </interface>"
|
||||
"</node>";
|
||||
|
||||
static const char *stack_tag_hints[] = {
|
||||
"synchronous",
|
||||
"private-synchronous",
|
||||
"x-canonical-private-synchronous",
|
||||
"x-dunst-stack-tag"
|
||||
};
|
||||
|
||||
static void on_get_capabilities(GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const GVariant *parameters,
|
||||
@ -120,6 +127,9 @@ static void on_get_capabilities(GDBusConnection *connection,
|
||||
g_variant_builder_add(builder, "s", "body");
|
||||
g_variant_builder_add(builder, "s", "body-hyperlinks");
|
||||
|
||||
for (int i = 0; i < sizeof(stack_tag_hints)/sizeof(*stack_tag_hints); ++i)
|
||||
g_variant_builder_add(builder, "s", stack_tag_hints[i]);
|
||||
|
||||
if (settings.markup != MARKUP_NO)
|
||||
g_variant_builder_add(builder, "s", "body-markup");
|
||||
|
||||
@ -245,6 +255,20 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
|
||||
n->progress = g_variant_get_uint32(dict_value);
|
||||
g_variant_unref(dict_value);
|
||||
}
|
||||
|
||||
/* Check for hints that define the stack_tag
|
||||
*
|
||||
* Only accept to first one we find.
|
||||
*/
|
||||
for (int i = 0; i < sizeof(stack_tag_hints)/sizeof(*stack_tag_hints); ++i) {
|
||||
dict_value = g_variant_lookup_value(content, stack_tag_hints[i], G_VARIANT_TYPE_STRING);
|
||||
if (dict_value) {
|
||||
n->stack_tag = g_variant_dup_string(dict_value, NULL);
|
||||
g_variant_unref(dict_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
|
@ -66,6 +66,7 @@ void notification_print(const struct notification *n)
|
||||
printf("\tframe: %s\n", n->colors[ColFrame]);
|
||||
printf("\tfullscreen: %s\n", enum_to_string_fullscreen(n->fullscreen));
|
||||
printf("\tprogress: %d\n", n->progress);
|
||||
printf("\tstack_tag: %s\n", (n->stack_tag ? n->stack_tag : ""));
|
||||
printf("\tid: %d\n", n->id);
|
||||
if (n->urls) {
|
||||
char *urls = string_replace_all("\n", "\t\t\n", g_strdup(n->urls));
|
||||
@ -251,6 +252,7 @@ void notification_unref(struct notification *n)
|
||||
g_free(n->colors[ColFG]);
|
||||
g_free(n->colors[ColBG]);
|
||||
g_free(n->colors[ColFrame]);
|
||||
g_free(n->stack_tag);
|
||||
|
||||
actions_free(n->actions);
|
||||
rawimage_free(n->raw_icon);
|
||||
|
@ -70,6 +70,8 @@ struct notification {
|
||||
const char *script;
|
||||
char *colors[3];
|
||||
|
||||
char *stack_tag; /**< stack notifications by tag */
|
||||
|
||||
/* Hints */
|
||||
bool transient; /**< timeout albeit user is idle */
|
||||
int progress; /**< percentage (-1: undefined) */
|
||||
|
61
src/queues.c
61
src/queues.c
@ -34,6 +34,7 @@ int next_notification_id = 1;
|
||||
bool pause_displayed = false;
|
||||
|
||||
static bool queues_stack_duplicate(struct notification *n);
|
||||
static bool queues_stack_by_tag(struct notification *n);
|
||||
|
||||
/* see queues.h */
|
||||
void queues_init(void)
|
||||
@ -123,6 +124,7 @@ static bool queues_notification_is_ready(const struct notification *n, bool full
|
||||
/* see queues.h */
|
||||
int queues_notification_insert(struct notification *n)
|
||||
{
|
||||
bool inserted = false;
|
||||
|
||||
/* do not display the message, if the message is empty */
|
||||
if (STR_EMPTY(n->msg)) {
|
||||
@ -146,14 +148,17 @@ int queues_notification_insert(struct notification *n)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n->id == 0) {
|
||||
if (!inserted && n->id != 0 && queues_notification_replace_id(n))
|
||||
inserted = true;
|
||||
else
|
||||
n->id = ++next_notification_id;
|
||||
if (!settings.stack_duplicates || !queues_stack_duplicate(n))
|
||||
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
||||
} else {
|
||||
if (!queues_notification_replace_id(n))
|
||||
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
||||
}
|
||||
|
||||
if (!inserted && STR_FULL(n->stack_tag) && queues_stack_by_tag(n))
|
||||
inserted = true;
|
||||
if (!inserted && settings.stack_duplicates && queues_stack_duplicate(n))
|
||||
inserted = true;
|
||||
if (!inserted)
|
||||
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
||||
|
||||
if (settings.print_notifications)
|
||||
notification_print(n);
|
||||
@ -170,7 +175,7 @@ int queues_notification_insert(struct notification *n)
|
||||
static bool queues_stack_duplicate(struct notification *n)
|
||||
{
|
||||
GQueue *allqueues[] = { displayed, waiting };
|
||||
for (int i = 0; i < sizeof(allqueues)/sizeof(GList*); i++) {
|
||||
for (int i = 0; i < sizeof(allqueues)/sizeof(GQueue*); i++) {
|
||||
for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter;
|
||||
iter = iter->next) {
|
||||
struct notification *orig = iter->data;
|
||||
@ -188,7 +193,7 @@ static bool queues_stack_duplicate(struct notification *n)
|
||||
n->dup_count = orig->dup_count;
|
||||
signal_notification_closed(orig, 1);
|
||||
|
||||
if ( allqueues[i] == displayed )
|
||||
if (allqueues[i] == displayed)
|
||||
n->start = time_monotonic_now();
|
||||
|
||||
notification_unref(orig);
|
||||
@ -200,11 +205,43 @@ static bool queues_stack_duplicate(struct notification *n)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the first notification of the same stack_tag
|
||||
*
|
||||
* @return true, if notification got stacked
|
||||
* @return false, if notification did not get stacked
|
||||
*/
|
||||
static bool queues_stack_by_tag(struct notification *new)
|
||||
{
|
||||
GQueue *allqueues[] = { displayed, waiting };
|
||||
for (int i = 0; i < sizeof(allqueues)/sizeof(GQueue*); i++) {
|
||||
for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter;
|
||||
iter = iter->next) {
|
||||
struct notification *old = iter->data;
|
||||
if (STR_FULL(old->stack_tag) && STR_EQ(old->stack_tag, new->stack_tag)) {
|
||||
iter->data = new;
|
||||
new->dup_count = old->dup_count;
|
||||
|
||||
signal_notification_closed(old, 1);
|
||||
|
||||
if (allqueues[i] == displayed) {
|
||||
new->start = time_monotonic_now();
|
||||
notification_run_script(new);
|
||||
}
|
||||
|
||||
notification_unref(old);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* see queues.h */
|
||||
bool queues_notification_replace_id(struct notification *new)
|
||||
{
|
||||
GQueue *allqueues[] = { displayed, waiting };
|
||||
for (int i = 0; i < sizeof(allqueues)/sizeof(GList*); i++) {
|
||||
for (int i = 0; i < sizeof(allqueues)/sizeof(GQueue*); i++) {
|
||||
for (GList *iter = g_queue_peek_head_link(allqueues[i]);
|
||||
iter;
|
||||
iter = iter->next) {
|
||||
@ -213,7 +250,7 @@ bool queues_notification_replace_id(struct notification *new)
|
||||
iter->data = new;
|
||||
new->dup_count = old->dup_count;
|
||||
|
||||
if ( allqueues[i] == displayed ) {
|
||||
if (allqueues[i] == displayed) {
|
||||
new->start = time_monotonic_now();
|
||||
notification_run_script(new);
|
||||
}
|
||||
@ -232,7 +269,7 @@ void queues_notification_close_id(int id, enum reason reason)
|
||||
struct notification *target = NULL;
|
||||
|
||||
GQueue *allqueues[] = { displayed, waiting };
|
||||
for (int i = 0; i < sizeof(allqueues)/sizeof(GList*); i++) {
|
||||
for (int i = 0; i < sizeof(allqueues)/sizeof(GQueue*); i++) {
|
||||
for (GList *iter = g_queue_peek_head_link(allqueues[i]); iter;
|
||||
iter = iter->next) {
|
||||
struct notification *n = iter->data;
|
||||
|
17
src/rules.c
17
src/rules.c
@ -47,6 +47,10 @@ void rule_apply(struct rule *r, struct notification *n)
|
||||
n->format = r->format;
|
||||
if (r->script)
|
||||
n->script = r->script;
|
||||
if (r->set_stack_tag) {
|
||||
g_free(n->stack_tag);
|
||||
n->stack_tag = g_strdup(r->set_stack_tag);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -73,6 +77,7 @@ void rule_init(struct rule *r)
|
||||
r->body = NULL;
|
||||
r->icon = NULL;
|
||||
r->category = NULL;
|
||||
r->stack_tag = NULL;
|
||||
r->msg_urgency = URG_NONE;
|
||||
r->timeout = -1;
|
||||
r->urgency = URG_NONE;
|
||||
@ -86,6 +91,7 @@ void rule_init(struct rule *r)
|
||||
r->bg = NULL;
|
||||
r->fc = NULL;
|
||||
r->format = NULL;
|
||||
r->set_stack_tag = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -93,11 +99,12 @@ void rule_init(struct rule *r)
|
||||
*/
|
||||
bool rule_matches_notification(struct rule *r, struct notification *n)
|
||||
{
|
||||
return ( (!r->appname || (n->appname && !fnmatch(r->appname, n->appname, 0)))
|
||||
&& (!r->summary || (n->summary && !fnmatch(r->summary, n->summary, 0)))
|
||||
&& (!r->body || (n->body && !fnmatch(r->body, n->body, 0)))
|
||||
&& (!r->icon || (n->icon && !fnmatch(r->icon, n->icon, 0)))
|
||||
&& (!r->category || (n->category && !fnmatch(r->category, n->category, 0)))
|
||||
return ( (!r->appname || (n->appname && !fnmatch(r->appname, n->appname, 0)))
|
||||
&& (!r->summary || (n->summary && !fnmatch(r->summary, n->summary, 0)))
|
||||
&& (!r->body || (n->body && !fnmatch(r->body, n->body, 0)))
|
||||
&& (!r->icon || (n->icon && !fnmatch(r->icon, n->icon, 0)))
|
||||
&& (!r->category || (n->category && !fnmatch(r->category, n->category, 0)))
|
||||
&& (!r->stack_tag || (n->stack_tag && !fnmatch(r->stack_tag, n->stack_tag, 0)))
|
||||
&& (r->match_transient == -1 || (r->match_transient == n->transient))
|
||||
&& (r->msg_urgency == URG_NONE || r->msg_urgency == n->urgency));
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ struct rule {
|
||||
char *body;
|
||||
char *icon;
|
||||
char *category;
|
||||
char *stack_tag;
|
||||
int msg_urgency;
|
||||
|
||||
/* actions */
|
||||
@ -32,6 +33,7 @@ struct rule {
|
||||
const char *format;
|
||||
const char *script;
|
||||
enum behavior_fullscreen fullscreen;
|
||||
char *set_stack_tag;
|
||||
};
|
||||
|
||||
extern GSList *rules;
|
||||
|
@ -368,7 +368,7 @@ void load_settings(char *cmdline_config_path)
|
||||
settings.hide_duplicate_count = option_get_bool(
|
||||
"global",
|
||||
"hide_duplicate_count", "-hide_duplicate_count", false,
|
||||
"Hide the count of merged notifications with the same content"
|
||||
"Hide the count of stacked notifications with the same content"
|
||||
);
|
||||
|
||||
settings.sticky_history = option_get_bool(
|
||||
@ -444,7 +444,7 @@ void load_settings(char *cmdline_config_path)
|
||||
settings.stack_duplicates = option_get_bool(
|
||||
"global",
|
||||
"stack_duplicates", "-stack_duplicates", true,
|
||||
"Merge multiple notifications with the same content"
|
||||
"Stack together notifications with the same content"
|
||||
);
|
||||
|
||||
settings.startup_notification = option_get_bool(
|
||||
@ -785,6 +785,7 @@ void load_settings(char *cmdline_config_path)
|
||||
r->body = ini_get_string(cur_section, "body", r->body);
|
||||
r->icon = ini_get_string(cur_section, "icon", r->icon);
|
||||
r->category = ini_get_string(cur_section, "category", r->category);
|
||||
r->stack_tag = ini_get_string(cur_section, "stack_tag", r->stack_tag);
|
||||
r->timeout = ini_get_time(cur_section, "timeout", r->timeout);
|
||||
|
||||
{
|
||||
@ -819,6 +820,7 @@ void load_settings(char *cmdline_config_path)
|
||||
g_free(c);
|
||||
}
|
||||
r->script = ini_get_path(cur_section, "script", NULL);
|
||||
r->set_stack_tag = ini_get_string(cur_section, "set_stack_tag", r->set_stack_tag);
|
||||
}
|
||||
|
||||
#ifndef STATIC_CONFIG
|
||||
|
Loading…
x
Reference in New Issue
Block a user