Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom indicators for actions and URLs #1216

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions docs/dunst.5.pod
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,14 @@ For a complete markup reference, see

=item B<%I> iconname (without its path)

=item B<%D> duplicate notification count

=item B<%A> custom action indicator

=item B<%C> action count

=item B<%U> custom URL indicator

=item B<%p> progress value ([ 0%] to [100%])

=item B<%n> progress value without any extra characters
Expand Down Expand Up @@ -404,10 +412,24 @@ it, summary, body, icon and urgency are all identical.

Hide the count of stacked duplicate notifications.

=item B<show_indicators> (values: [true/false], default: true)
=item B<show_indicators> DEPRECATED (values: [true/false], default: true)

Show an indicator if a notification contains actions and/or open-able URLs. See
ACTIONS below for further details.
ACTIONS below for further details. This setting is deprecated, please use
action_indicator and url_indicator instead.

=item B<show_action_count> (values: [true/false], default: true)

Includes the number of actions available in the default action indicator.
If %C is used in the format string, it will be shown regardless of this setting.

=item B<action_indicator> (default: "A")

Indicator used in the format string replacing %A when the notification has actions.

=item B<url_indicator> (default: "U")

Indicator used in the format string replacing %U when the notification has URLs.

=item B<icon_path> (default: "/usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/")

Expand Down
13 changes: 12 additions & 1 deletion dunstrc
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@
# %b body
# %i iconname (including its path)
# %I iconname (without its path)
# %D Duplicate notification count
# %A Action indicator
# %C Action count
# %U URL indicator
# %p progress value if set ([ 0%] to [100%]) or nothing
# %n progress value if set without any extra characters
# %% Literal %
Expand Down Expand Up @@ -191,9 +195,16 @@
# Hide the count of stacked notifications with the same content
hide_duplicate_count = false

# Display indicators for URLs (U) and actions (A).
# (DEPRECATED) Display default indicators for URLs (U) and actions (A)
show_indicators = yes

# Prefix default action indicator with action count (for custom indicators use %C)
show_action_count = yes

# Custom indicators
action_indicator = "A"
url_indicator = "U"

### Icons ###

# Recursive icon lookup. You can set a single theme, instead of having to
Expand Down
80 changes: 66 additions & 14 deletions src/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,38 @@ static void notification_format_message(struct notification *n)
n->progress != -1 ? pg : "",
MARKUP_NO);
break;
case 'D':
char *dup_count = g_strdup_printf("(%d)", n->dup_count);
notification_replace_single_field(
&n->msg,
&substr,
n->dup_count > 0 ? dup_count : "",
MARKUP_NO);
g_free(dup_count);
break;
case 'A':
notification_replace_single_field(
&n->msg,
&substr,
g_hash_table_size(n->actions) ? settings.action_indicator : "",
MARKUP_NO);
break;
case 'C':
char *action_count = g_strdup_printf("%d", g_hash_table_size(n->actions));
notification_replace_single_field(
&n->msg,
&substr,
action_count,
MARKUP_NO);
g_free(action_count);
break;
case 'U':
notification_replace_single_field(
&n->msg,
&substr,
n->urls ? settings.url_indicator : "",
MARKUP_NO);
break;
case '%':
notification_replace_single_field(
&n->msg,
Expand Down Expand Up @@ -651,21 +683,41 @@ void notification_update_text_to_render(struct notification *n)

char *buf = NULL;

char *prev_indicators = NULL;
char *indicators = NULL;

char *msg = g_strchomp(n->msg);

/* print dup_count and msg */
if ((n->dup_count > 0 && !settings.hide_duplicate_count)
&& (g_hash_table_size(n->actions) || n->urls) && settings.show_indicators) {
buf = g_strdup_printf("(%d%s%s) %s",
n->dup_count,
g_hash_table_size(n->actions) ? "A" : "",
n->urls ? "U" : "", msg);
} else if ((g_hash_table_size(n->actions) || n->urls) && settings.show_indicators) {
buf = g_strdup_printf("(%s%s) %s",
g_hash_table_size(n->actions) ? "A" : "",
n->urls ? "U" : "", msg);
} else if (n->dup_count > 0 && !settings.hide_duplicate_count) {
buf = g_strdup_printf("(%d) %s", n->dup_count, msg);
if (n->dup_count > 0 && !settings.hide_duplicate_count) {
indicators = g_strdup_printf("%d ", n->dup_count);
}

if (settings.show_indicators) {
if(g_hash_table_size(n->actions)) {
prev_indicators = indicators;
char *action_count = g_strdup_printf("%d", g_hash_table_size(n->actions));

indicators = g_strdup_printf("%s%s%s",
prev_indicators ? prev_indicators : "",
settings.show_action_count ? action_count : "",
settings.action_indicator
);

g_free(prev_indicators);
g_free(action_count);
}
if(n->urls) {
prev_indicators = indicators;

indicators = g_strdup_printf("%s%s", prev_indicators ? prev_indicators : "", settings.url_indicator);

g_free(prev_indicators);
}
}

if (indicators) {
buf = g_strdup_printf("(%s) %s", indicators, msg);
g_free(indicators);
} else {
buf = g_strdup(msg);
}
Expand Down Expand Up @@ -705,7 +757,7 @@ void notification_update_text_to_render(struct notification *n)
void notification_do_action(struct notification *n)
{
assert(n->default_action_name);

if (g_hash_table_size(n->actions)) {
if (g_hash_table_contains(n->actions, n->default_action_name)) {
signal_action_invoked(n, n->default_action_name);
Expand Down
3 changes: 3 additions & 0 deletions src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ struct settings {
int sticky_history;
int history_length;
int show_indicators;
int show_action_count;
char *action_indicator;
char *url_indicator;
int ignore_dbusclose;
int ignore_newline;
int line_height;
Expand Down
34 changes: 32 additions & 2 deletions src/settings_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ struct setting {
/*
* How to add/change a rule
* ------------------------
*
*
* - Add variable to `struct rules` in `rules.h` (make sure to read the comment
* at the top of the struct)
* - Add variable to to `struct notification` in `notification.h`
Expand Down Expand Up @@ -957,13 +957,43 @@ static const struct setting allowed_settings[] = {
{
.name = "show_indicators",
.section = "global",
.description = "Show indicators for actions \"(A)\" and URLs \"(U)\"",
.description = "Show default indicators for actions \"(A)\" and URLs \"(U)\"",
.type = TYPE_CUSTOM,
.default_value = "true",
.value = &settings.show_indicators,
.parser = string_parse_enum,
.parser_data = boolean_enum_data,
},
{
.name = "show_action_count",
.section = "global",
.description = "Show the number of actions available for a notification",
.type = TYPE_CUSTOM,
.default_value = "true",
.value = &settings.show_action_count,
.parser = string_parse_enum,
.parser_data = boolean_enum_data,
},
{
.name = "action_indicator",
.section = "global",
.description = "String to show when there are actions",
.type = TYPE_STRING,
.default_value = "A",
.value = &settings.action_indicator,
.parser = NULL,
.parser_data = NULL,
},
{
.name = "url_indicator",
.section = "global",
.description = "String to show when there are URLs",
.type = TYPE_STRING,
.default_value = "U",
.value = &settings.url_indicator,
.parser = NULL,
.parser_data = NULL,
},
{
.name = "separator_height",
.section = "global",
Expand Down
52 changes: 51 additions & 1 deletion test/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,50 @@ TEST test_notification_maxlength(void)
PASS();
}

TEST test_notification_with_default_indicators(void)
{
struct notification *n = notification_create();

char *dummy_action = g_strdup("dummy_action");

n->summary = "sum";
n->body = "bod";
n->urls = "https://example.com";
g_hash_table_insert(n->actions, dummy_action, dummy_action);

n->msg = "foo";

notification_update_text_to_render(n);

ASSERT(STRN_EQ(n->text_to_render, "(1AU) foo", 9));

g_free(dummy_action);
notification_unref(n);

PASS();
}


TEST test_notification_with_custom_indicators(void)
{
struct notification *n = notification_create();

char *dummy_action = g_strdup("dummy_action");

n->format = "%C %A %U";
n->urls = "https://example.com";
g_hash_table_insert(n->actions, dummy_action, dummy_action);

notification_format_message(n);

ASSERT(STRN_EQ(n->msg, "1 A U", 5));

g_free(dummy_action);
notification_unref(n);

PASS();
}


SUITE(suite_notification)
{
Expand Down Expand Up @@ -256,11 +300,15 @@ SUITE(suite_notification)
"%b", "Look at my shiny <notification>",
"%I", "icoknpath.png",
"%i", "/this/is/my/icoknpath.png",
"%D", "",
"%A", "",
"%C", "0",
"%U", "",
"%p", "[ 95%]",
"%n", "95",
"%%", "%",
"%", "%",
"%UNKNOWN", "%UNKNOWN",
"%unknown", "%unknown",
NULL
};

Expand All @@ -274,6 +322,8 @@ SUITE(suite_notification)
g_clear_pointer(&a, notification_unref);

RUN_TEST(test_notification_maxlength);
RUN_TEST(test_notification_with_default_indicators);
RUN_TEST(test_notification_with_custom_indicators);
}

/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
Loading