Merge pull request #592 from bebehei/desktop-entry
Desktop entry filters.
This commit is contained in:
commit
dd6320a0a9
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Introduce new desktop-entry filter (#470)
|
||||||
- Remove libxdg-basedir dependency (GLib's function is used instead)
|
- Remove libxdg-basedir dependency (GLib's function is used instead)
|
||||||
- `fullscreen` rule to hide notifications when a fullscreen window is active
|
- `fullscreen` rule to hide notifications when a fullscreen window is active
|
||||||
- When new notifications arrive, but display is full, important notifications don't
|
- When new notifications arrive, but display is full, important notifications don't
|
||||||
|
@ -610,11 +610,34 @@ matched.
|
|||||||
|
|
||||||
=item B<filtering>
|
=item B<filtering>
|
||||||
|
|
||||||
Notifications can be matched for any of the following attributes: appname,
|
Notifications can be matched for any of the following attributes:
|
||||||
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
|
=over 4
|
||||||
the urgency of the notification, it is named so to not conflict with trying to
|
|
||||||
modify the urgency.
|
=item C<appname> (discouraged, see desktop_entry)
|
||||||
|
|
||||||
|
=item C<body>
|
||||||
|
|
||||||
|
=item C<category>
|
||||||
|
|
||||||
|
=item C<desktop_entry>
|
||||||
|
|
||||||
|
=item C<icon>
|
||||||
|
|
||||||
|
=item C<msg_urgency>
|
||||||
|
|
||||||
|
=item C<stack_tag>
|
||||||
|
|
||||||
|
=item C<summary>
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
C<msg_urgency> is the urgency of the notification, it is named so to not conflict
|
||||||
|
with trying to modify the urgency.
|
||||||
|
|
||||||
|
Instead of the appname filter, it's recommended to use the desktop_entry filter.
|
||||||
|
GLib based applications export their desktop-entry name. In comparison to the appname,
|
||||||
|
the desktop-entry won't get localized.
|
||||||
|
|
||||||
To define a matching rule simply assign the specified value to the value that
|
To define a matching rule simply assign the specified value to the value that
|
||||||
should be matched, for example:
|
should be matched, for example:
|
||||||
@ -629,9 +652,31 @@ Shell-like globing is supported.
|
|||||||
|
|
||||||
=item B<modifying>
|
=item B<modifying>
|
||||||
|
|
||||||
The following attributes can be overridden: timeout, urgency, foreground,
|
The following attributes can be overridden:
|
||||||
background, frame_color, new_icon, set_transient, format, fullscreen,
|
|
||||||
set_stack_tag where, as with the filtering attributes, each one corresponds to
|
=over 4
|
||||||
|
|
||||||
|
=item C<background>
|
||||||
|
|
||||||
|
=item C<foreground>
|
||||||
|
|
||||||
|
=item C<format>
|
||||||
|
|
||||||
|
=item C<frame_color>
|
||||||
|
|
||||||
|
=item C<fullscreen>
|
||||||
|
|
||||||
|
=item C<new_icon>
|
||||||
|
|
||||||
|
=item C<set_stack_tag>
|
||||||
|
|
||||||
|
=item C<timeout>
|
||||||
|
|
||||||
|
=item C<urgency>
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
As with the filtering attributes, each one corresponds to
|
||||||
the respective notification attribute to be modified.
|
the respective notification attribute to be modified.
|
||||||
|
|
||||||
As with filtering, to make a rule modify an attribute simply assign it in the
|
As with filtering, to make a rule modify an attribute simply assign it in the
|
||||||
|
30
dunstrc
30
dunstrc
@ -297,12 +297,34 @@
|
|||||||
|
|
||||||
# Every section that isn't one of the above is interpreted as a rules to
|
# Every section that isn't one of the above is interpreted as a rules to
|
||||||
# override settings for certain messages.
|
# 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",
|
# Messages can be matched by
|
||||||
# "background", "frame_color", "new_icon" and "format", "fullscreen",
|
# appname (discouraged, see desktop_entry)
|
||||||
# "stack_tag".
|
# body
|
||||||
|
# category
|
||||||
|
# desktop_entry
|
||||||
|
# icon
|
||||||
|
# msg_urgency
|
||||||
|
# stack_tag
|
||||||
|
# summary
|
||||||
|
#
|
||||||
|
# and you can override the
|
||||||
|
# background
|
||||||
|
# foreground
|
||||||
|
# format
|
||||||
|
# frame_color
|
||||||
|
# fullscreen
|
||||||
|
# new_icon
|
||||||
|
# set_stack_tag
|
||||||
|
# timeout
|
||||||
|
# urgency
|
||||||
|
#
|
||||||
# Shell-like globbing will get expanded.
|
# Shell-like globbing will get expanded.
|
||||||
#
|
#
|
||||||
|
# Instead of the appname filter, it's recommended to use the desktop_entry filter.
|
||||||
|
# GLib based applications export their desktop-entry name. In comparison to the appname,
|
||||||
|
# the desktop-entry won't get localized.
|
||||||
|
#
|
||||||
# SCRIPTING
|
# SCRIPTING
|
||||||
# You can specify a script that gets run when the rule matches by
|
# You can specify a script that gets run when the rule matches by
|
||||||
# setting the "script" option.
|
# setting the "script" option.
|
||||||
|
@ -227,6 +227,11 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
|
|||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((dict_value = g_variant_lookup_value(hints, "desktop-entry", G_VARIANT_TYPE_STRING))) {
|
||||||
|
n->desktop_entry = g_variant_dup_string(dict_value, NULL);
|
||||||
|
g_variant_unref(dict_value);
|
||||||
|
}
|
||||||
|
|
||||||
if ((dict_value = g_variant_lookup_value(hints, "image-path", G_VARIANT_TYPE_STRING))) {
|
if ((dict_value = g_variant_lookup_value(hints, "image-path", G_VARIANT_TYPE_STRING))) {
|
||||||
g_free(n->iconname);
|
g_free(n->iconname);
|
||||||
n->iconname = g_variant_dup_string(dict_value, NULL);
|
n->iconname = g_variant_dup_string(dict_value, NULL);
|
||||||
|
@ -56,6 +56,7 @@ void notification_print(const struct notification *n)
|
|||||||
printf("\ticon: '%s'\n", n->iconname);
|
printf("\ticon: '%s'\n", n->iconname);
|
||||||
printf("\traw_icon set: %s\n", (n->icon_id && !STR_EQ(n->iconname, n->icon_id)) ? "true" : "false");
|
printf("\traw_icon set: %s\n", (n->icon_id && !STR_EQ(n->iconname, n->icon_id)) ? "true" : "false");
|
||||||
printf("\ticon_id: '%s'\n", n->icon_id);
|
printf("\ticon_id: '%s'\n", n->icon_id);
|
||||||
|
printf("\tdesktop_entry: '%s'\n", n->desktop_entry ? n->desktop_entry : "");
|
||||||
printf("\tcategory: %s\n", n->category);
|
printf("\tcategory: %s\n", n->category);
|
||||||
printf("\ttimeout: %ld\n", n->timeout/1000);
|
printf("\ttimeout: %ld\n", n->timeout/1000);
|
||||||
printf("\turgency: %s\n", notification_urgency_to_string(n->urgency));
|
printf("\turgency: %s\n", notification_urgency_to_string(n->urgency));
|
||||||
@ -225,6 +226,7 @@ void notification_unref(struct notification *n)
|
|||||||
g_free(n->colors.bg);
|
g_free(n->colors.bg);
|
||||||
g_free(n->colors.frame);
|
g_free(n->colors.frame);
|
||||||
g_free(n->stack_tag);
|
g_free(n->stack_tag);
|
||||||
|
g_free(n->desktop_entry);
|
||||||
|
|
||||||
g_hash_table_unref(n->actions);
|
g_hash_table_unref(n->actions);
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ struct notification {
|
|||||||
char *summary;
|
char *summary;
|
||||||
char *body;
|
char *body;
|
||||||
char *category;
|
char *category;
|
||||||
|
char *desktop_entry; /**< The desktop entry hint sent via every GApplication */
|
||||||
enum urgency urgency;
|
enum urgency urgency;
|
||||||
|
|
||||||
GdkPixbuf *icon; /**< The raw cached icon data used to draw */
|
GdkPixbuf *icon; /**< The raw cached icon data used to draw */
|
||||||
|
42
src/rules.c
42
src/rules.c
@ -63,32 +63,25 @@ void rule_apply_all(struct notification *n)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
struct rule *rule_new(void)
|
||||||
* Initialize rule with default values.
|
|
||||||
*/
|
|
||||||
void rule_init(struct rule *r)
|
|
||||||
{
|
{
|
||||||
r->name = NULL;
|
struct rule *r = g_malloc0(sizeof(struct rule));
|
||||||
r->appname = NULL;
|
|
||||||
r->summary = NULL;
|
|
||||||
r->body = NULL;
|
|
||||||
r->icon = NULL;
|
|
||||||
r->category = NULL;
|
|
||||||
r->stack_tag = NULL;
|
|
||||||
r->msg_urgency = URG_NONE;
|
r->msg_urgency = URG_NONE;
|
||||||
r->timeout = -1;
|
r->timeout = -1;
|
||||||
r->urgency = URG_NONE;
|
r->urgency = URG_NONE;
|
||||||
r->fullscreen = FS_NULL;
|
r->fullscreen = FS_NULL;
|
||||||
r->markup = MARKUP_NULL;
|
r->markup = MARKUP_NULL;
|
||||||
r->new_icon = NULL;
|
|
||||||
r->history_ignore = false;
|
r->history_ignore = false;
|
||||||
r->match_transient = -1;
|
r->match_transient = -1;
|
||||||
r->set_transient = -1;
|
r->set_transient = -1;
|
||||||
r->fg = NULL;
|
|
||||||
r->bg = NULL;
|
return r;
|
||||||
r->fc = NULL;
|
}
|
||||||
r->format = NULL;
|
|
||||||
r->set_stack_tag = NULL;
|
static inline bool rule_field_matches_string(const char *value, const char *pattern)
|
||||||
|
{
|
||||||
|
return !pattern || (value && !fnmatch(pattern, value, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -96,13 +89,14 @@ void rule_init(struct rule *r)
|
|||||||
*/
|
*/
|
||||||
bool rule_matches_notification(struct rule *r, struct notification *n)
|
bool rule_matches_notification(struct rule *r, struct notification *n)
|
||||||
{
|
{
|
||||||
return ( (!r->appname || (n->appname && !fnmatch(r->appname, n->appname, 0)))
|
return (r->msg_urgency == URG_NONE || r->msg_urgency == n->urgency)
|
||||||
&& (!r->summary || (n->summary && !fnmatch(r->summary, n->summary, 0)))
|
|
||||||
&& (!r->body || (n->body && !fnmatch(r->body, n->body, 0)))
|
|
||||||
&& (!r->icon || (n->iconname && !fnmatch(r->icon, n->iconname,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->match_transient == -1 || (r->match_transient == n->transient))
|
||||||
&& (r->msg_urgency == URG_NONE || r->msg_urgency == n->urgency));
|
&& rule_field_matches_string(n->appname, r->appname)
|
||||||
|
&& rule_field_matches_string(n->desktop_entry, r->desktop_entry)
|
||||||
|
&& rule_field_matches_string(n->summary, r->summary)
|
||||||
|
&& rule_field_matches_string(n->body, r->body)
|
||||||
|
&& rule_field_matches_string(n->iconname, r->icon)
|
||||||
|
&& rule_field_matches_string(n->category, r->category)
|
||||||
|
&& rule_field_matches_string(n->stack_tag, r->stack_tag);
|
||||||
}
|
}
|
||||||
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
@ -17,6 +17,7 @@ struct rule {
|
|||||||
char *icon;
|
char *icon;
|
||||||
char *category;
|
char *category;
|
||||||
char *stack_tag;
|
char *stack_tag;
|
||||||
|
char *desktop_entry;
|
||||||
int msg_urgency;
|
int msg_urgency;
|
||||||
|
|
||||||
/* actions */
|
/* actions */
|
||||||
@ -38,7 +39,13 @@ struct rule {
|
|||||||
|
|
||||||
extern GSList *rules;
|
extern GSList *rules;
|
||||||
|
|
||||||
void rule_init(struct rule *r);
|
/**
|
||||||
|
* Allocate a new rule. The rule is fully initialised.
|
||||||
|
*
|
||||||
|
* @returns A new initialised rule.
|
||||||
|
*/
|
||||||
|
struct rule *rule_new(void);
|
||||||
|
|
||||||
void rule_apply(struct rule *r, struct notification *n);
|
void rule_apply(struct rule *r, struct notification *n);
|
||||||
void rule_apply_all(struct notification *n);
|
void rule_apply_all(struct notification *n);
|
||||||
bool rule_matches_notification(struct rule *r, struct notification *n);
|
bool rule_matches_notification(struct rule *r, struct notification *n);
|
||||||
|
@ -688,8 +688,7 @@ void load_settings(char *cmdline_config_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!r) {
|
if (!r) {
|
||||||
r = g_malloc(sizeof(struct rule));
|
r = rule_new();
|
||||||
rule_init(r);
|
|
||||||
rules = g_slist_insert(rules, r, -1);
|
rules = g_slist_insert(rules, r, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,6 +724,7 @@ void load_settings(char *cmdline_config_path)
|
|||||||
r->history_ignore = ini_get_bool(cur_section, "history_ignore", r->history_ignore);
|
r->history_ignore = ini_get_bool(cur_section, "history_ignore", r->history_ignore);
|
||||||
r->match_transient = ini_get_bool(cur_section, "match_transient", r->match_transient);
|
r->match_transient = ini_get_bool(cur_section, "match_transient", r->match_transient);
|
||||||
r->set_transient = ini_get_bool(cur_section, "set_transient", r->set_transient);
|
r->set_transient = ini_get_bool(cur_section, "set_transient", r->set_transient);
|
||||||
|
r->desktop_entry = ini_get_string(cur_section, "desktop_entry", r->desktop_entry);
|
||||||
{
|
{
|
||||||
char *c = ini_get_string(
|
char *c = ini_get_string(
|
||||||
cur_section,
|
cur_section,
|
||||||
|
34
test/dbus.c
34
test/dbus.c
@ -551,6 +551,39 @@ TEST test_hint_category(void)
|
|||||||
PASS();
|
PASS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST test_hint_desktop_entry(void)
|
||||||
|
{
|
||||||
|
struct notification *n;
|
||||||
|
struct dbus_notification *n_dbus;
|
||||||
|
const char *desktop_entry = "org.dunst-project.dunst";
|
||||||
|
|
||||||
|
gsize len = queues_length_waiting();
|
||||||
|
|
||||||
|
n_dbus = dbus_notification_new();
|
||||||
|
n_dbus->app_name = "dunstteststack";
|
||||||
|
n_dbus->app_icon = "NONE";
|
||||||
|
n_dbus->summary = "test_hint_desktopentry";
|
||||||
|
n_dbus->body = "Summary of my desktop_entry";
|
||||||
|
|
||||||
|
g_hash_table_insert(n_dbus->hints,
|
||||||
|
g_strdup("desktop-entry"),
|
||||||
|
g_variant_ref_sink(g_variant_new_string(desktop_entry)));
|
||||||
|
|
||||||
|
guint id;
|
||||||
|
ASSERT(dbus_notification_fire(n_dbus, &id));
|
||||||
|
ASSERT(id != 0);
|
||||||
|
|
||||||
|
ASSERT_EQ(queues_length_waiting(), len+1);
|
||||||
|
|
||||||
|
n = queues_debug_find_notification_by_id(id);
|
||||||
|
|
||||||
|
ASSERT_STR_EQ(desktop_entry, n->desktop_entry);
|
||||||
|
|
||||||
|
dbus_notification_free(n_dbus);
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
TEST test_hint_urgency(void)
|
TEST test_hint_urgency(void)
|
||||||
{
|
{
|
||||||
static char msg[50];
|
static char msg[50];
|
||||||
@ -779,6 +812,7 @@ gpointer run_threaded_tests(gpointer data)
|
|||||||
RUN_TEST(test_hint_progress);
|
RUN_TEST(test_hint_progress);
|
||||||
RUN_TEST(test_hint_icons);
|
RUN_TEST(test_hint_icons);
|
||||||
RUN_TEST(test_hint_category);
|
RUN_TEST(test_hint_category);
|
||||||
|
RUN_TEST(test_hint_desktop_entry);
|
||||||
RUN_TEST(test_hint_urgency);
|
RUN_TEST(test_hint_urgency);
|
||||||
RUN_TEST(test_hint_raw_image);
|
RUN_TEST(test_hint_raw_image);
|
||||||
RUN_TEST(test_dbus_notify_colors);
|
RUN_TEST(test_dbus_notify_colors);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user