Merge pull request #552 from Gravemind/x-canonical-private-synchronous

Implement x-canonical-private-synchronous hint
This commit is contained in:
Nikos Tsipinakis 2018-11-11 19:55:05 +02:00 committed by GitHub
commit 27c6a1682d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 114 additions and 28 deletions

View File

@ -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
View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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) */

View File

@ -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;

View File

@ -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));
}

View File

@ -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;

View File

@ -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