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

Add multiple pause levels #1193

Merged
merged 13 commits into from
Nov 9, 2023
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ If you want to take a break and not receive any notifications for a while, just
pause dunst. All notifications will be saved for you to catch up
later.

Additionally, you can set a numeric pause level, which allows you to pause dunst
selectively for some notifications, where more urgent notifications get through,
but less urgent stay paused.

## 🕘 History

Catch an unread notification disappearing from the corner of your eye? Just tap
Expand Down
2 changes: 2 additions & 0 deletions contrib/_dunstctl.zshcomp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ case $state in
'history-pop:Pop the latest notification from history or optionally the notification with given ID.'
'is-paused:Check if dunst is running or paused'
'set-paused:Set the pause status'
'get-paused-level:Get current dunst's pause level'
'set-paused-level:Set current dunst's pause level'
'rule:Enable or disable a rule by its name'
'debug:Print debugging information'
'help:Show this help'
Expand Down
16 changes: 14 additions & 2 deletions docs/dunstctl.pod
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,20 @@ will be kept but not shown until it is unpaused.
=item B<set-paused> true/false/toggle

Set the paused status of dunst. If false, dunst is running normally, if true,
dunst is paused. See the is-paused command and the dunst man page for more
information.
dunst is paused (with maximum pause level of 100).
See the is-paused command and the dunst man page for more information.

=item B<get-pause-level>

Get current dunst's pause level, where 0 is not paused and 100 is maximally paused.

This can be combined with notification's override_pause_level to selectively display specific notifications while paused.

=item B<set-pause-level> [level]

Set the pause level, where 0 is not paused and 100 is maximally paused.

This can be combined with notification's override_pause_level to selectively display specific notifications while paused.

=item B<debug>

Expand Down
27 changes: 25 additions & 2 deletions dunstctl
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ show_help() {
notification with given ID.
history-rm [ID] Remove the notification from
history with given ID.
is-paused Check if dunst is running or paused
set-paused [true|false|toggle] Set the pause status
is-paused Check if pause level is > 0
set-paused [true|false|toggle] Set the pause status
get-paused-level Get the current pause level
matejdro marked this conversation as resolved.
Show resolved Hide resolved
set-paused-level [level] Set the pause level
rule name [enable|disable|toggle] Enable or disable a rule by its name
debug Print debugging information
help Show this help
Expand Down Expand Up @@ -132,6 +134,27 @@ case "${1:-}" in
&& die "No valid rule state parameter specified. Please give either 'enable', 'disable' or 'toggle'"
method_call "${DBUS_IFAC_DUNST}.RuleEnable" "string:${2:-1}" "int32:${state}" >/dev/null
;;
"get-paused-level")
property_get pauseLevel | ( read -r _ _ paused; printf "%s\n" "${paused}"; )
;;
"set-paused-level")
[ "${2:-}" ] \
|| die "No status parameter specified. Please give a number as paused parameter."
[ "$2" ] && [ -z "${2//[0-9]}" ] \
|| die "Please give a number as paused level parameter."
property_set pauseLevel variant:uint32:"$2"
;;
"rule")
[ "${2:-}" ] \
|| die "No rule name parameter specified. Please give the rule name"
state=nope
[ "${3}" = "disable" ] && state=0
[ "${3}" = "enable" ] && state=1
[ "${3}" = "toggle" ] && state=2
[ "${state}" = "nope" ] \
&& die "No valid rule state parameter specified. Please give either 'enable', 'disable' or 'toggle'"
method_call "${DBUS_IFAC_DUNST}.RuleEnable" "string:${2:-1}" "int32:${state}" >/dev/null
;;
"help"|"--help"|"-h")
show_help
;;
Expand Down
6 changes: 6 additions & 0 deletions dunstrc
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@
# Maximum amount of notifications kept in history
history_length = 20

### DND ###
matejdro marked this conversation as resolved.
Show resolved Hide resolved

# Allow this notification to appear even when paused. Notification will appear whenever notification's override_pause_level >= dunst's paused level.
# This can be used to set partial pause modes, where more urgent notifications get through, but less urgent stay paused.
override_pause_level = 0

### Misc/Advanced ###

# dmenu path.
Expand Down
29 changes: 26 additions & 3 deletions src/dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ static const char *introspection_xml =
" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"true\"/>"
" </property>"

" <property name=\"pauseLevel\" type=\"u\" access=\"readwrite\">"
" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"true\"/>"
" </property>"

" <property name=\"displayedLength\" type=\"u\" access=\"read\" />"
" <property name=\"historyLength\" type=\"u\" access=\"read\" />"
" <property name=\"waitingLength\" type=\"u\" access=\"read\" />"
Expand Down Expand Up @@ -923,7 +927,9 @@ GVariant *dbus_cb_dunst_Properties_Get(GDBusConnection *connection,
struct dunst_status status = dunst_status_get();

if (STR_EQ(property_name, "paused")) {
return g_variant_new_boolean(!status.running);
return g_variant_new_boolean(status.pause_level != 0);
} else if (STR_EQ(property_name, "pauseLevel")) {
return g_variant_new_uint32(status.pause_level);
} else if (STR_EQ(property_name, "displayedLength")) {
unsigned int displayed = queues_length_displayed();
return g_variant_new_uint32(displayed);
Expand All @@ -949,15 +955,32 @@ gboolean dbus_cb_dunst_Properties_Set(GDBusConnection *connection,
GError **error,
gpointer user_data)
{
int targetPauseLevel = -1;
if (STR_EQ(property_name, "paused")) {
dunst_status(S_RUNNING, !g_variant_get_boolean(value));
if (g_variant_get_boolean(value)) {
targetPauseLevel = MAX_PAUSE_LEVEL;
} else {
targetPauseLevel = 0;
}
} else if STR_EQ(property_name, "pauseLevel") {
targetPauseLevel = g_variant_get_uint32(value);
if (targetPauseLevel > MAX_PAUSE_LEVEL) {
targetPauseLevel = MAX_PAUSE_LEVEL;
}
}

if (targetPauseLevel >= 0) {
dunst_status_int(S_PAUSE_LEVEL, targetPauseLevel);
wake_up();

GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT);
GVariantBuilder *invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE_STRING_ARRAY);
g_variant_builder_add(builder,
"{sv}",
"paused", g_variant_new_boolean(g_variant_get_boolean(value)));
"paused", g_variant_new_boolean(targetPauseLevel != 0));
g_variant_builder_add(builder,
"{sv}",
"pauseLevel", g_variant_new_uint32(targetPauseLevel));
g_dbus_connection_emit_signal(connection,
NULL,
object_path,
Expand Down
22 changes: 16 additions & 6 deletions src/dunst.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,21 @@ void dunst_status(const enum dunst_status_field field,
case S_IDLE:
status.idle = value;
break;
case S_RUNNING:
status.running = value;
default:
LOG_E("Invalid %s enum value in %s:%d for bool type", "dunst_status", __FILE__, __LINE__);
break;
}
}

void dunst_status_int(const enum dunst_status_field field,
int value)
{
switch (field) {
case S_PAUSE_LEVEL:
status.pause_level = value;
break;
default:
LOG_E("Invalid %s enum value in %s:%d", "dunst_status", __FILE__, __LINE__);
LOG_E("Invalid %s enum value in %s:%d fot int type", "dunst_status", __FILE__, __LINE__);
break;
}
}
Expand Down Expand Up @@ -123,15 +133,15 @@ static gboolean run(void *data)

gboolean pause_signal(gpointer data)
{
dunst_status(S_RUNNING, false);
dunst_status_int(S_PAUSE_LEVEL, MAX_PAUSE_LEVEL);
wake_up();

return G_SOURCE_CONTINUE;
}

gboolean unpause_signal(gpointer data)
{
dunst_status(S_RUNNING, true);
dunst_status_int(S_PAUSE_LEVEL, 0);
wake_up();

return G_SOURCE_CONTINUE;
Expand All @@ -156,7 +166,7 @@ static void teardown(void)
int dunst_main(int argc, char *argv[])
{

dunst_status(S_RUNNING, true);
dunst_status_int(S_PAUSE_LEVEL, 0);
dunst_status(S_IDLE, false);

queues_init();
Expand Down
8 changes: 6 additions & 2 deletions src/dunst.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@

#include "notification.h"

#define MAX_PAUSE_LEVEL 100

//!< A structure to describe dunst's global window status
struct dunst_status {
bool fullscreen; //!< a fullscreen window is currently focused
bool running; //!< set true if dunst is currently running
int pause_level; //!< current pause level. 0 = all notifications come through, 100 = no notifications come through
bool idle; //!< set true if the user is idle
};

enum dunst_status_field {
S_FULLSCREEN,
S_IDLE,
S_RUNNING,
S_PAUSE_LEVEL,
};

/**
Expand All @@ -30,6 +32,8 @@ enum dunst_status_field {
*/
void dunst_status(const enum dunst_status_field field,
bool value);
void dunst_status_int(const enum dunst_status_field field,
int value);

struct dunst_status dunst_status_get(void);

Expand Down
2 changes: 2 additions & 0 deletions src/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,8 @@ void notification_init(struct notification *n)
if (n->progress < 0)
n->progress = -1;

n->override_pause_level = 0;

/* Process rules */
rule_apply_all(n);

Expand Down
1 change: 1 addition & 0 deletions src/notification.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct notification {
char *category;
char *desktop_entry; /**< The desktop entry hint sent via every GApplication */
enum urgency urgency;
int override_pause_level;

cairo_surface_t *icon; /**< The raw cached icon data used to draw */
char *icon_id; /**< Plain icon information, which acts as the icon's id.
Expand Down
5 changes: 4 additions & 1 deletion src/queues.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ static void queues_swap_notifications(GQueue *queueA,
*/
static bool queues_notification_is_ready(const struct notification *n, struct dunst_status status, bool shown)
{
ASSERT_OR_RET(status.running, false);
if (status.pause_level > n->override_pause_level) {
return false;
}

if (status.fullscreen && shown)
return n && n->fullscreen != FS_PUSHBACK;
else if (status.fullscreen && !shown)
Expand Down
3 changes: 3 additions & 0 deletions src/rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ void rule_apply(struct rule *r, struct notification *n)
g_free(n->stack_tag);
n->stack_tag = g_strdup(r->set_stack_tag);
}
if (r->override_pause_level != -1) {
n->override_pause_level = r->override_pause_level;
}
}

/*
Expand Down
1 change: 1 addition & 0 deletions src/rules.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct rule {
int icon_position;
int min_icon_size;
int max_icon_size;
int override_pause_level;
char *new_icon;
char *fg;
char *bg;
Expand Down
12 changes: 12 additions & 0 deletions src/settings_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ static const struct rule empty_rule = {
.progress_bar_alignment = -1,
.min_icon_size = -1,
.max_icon_size = -1,
.override_pause_level = -1
};


Expand Down Expand Up @@ -760,6 +761,17 @@ static const struct setting allowed_settings[] = {
.parser_data = NULL,
.rule_offset = offsetof(struct rule, max_icon_size),
},
{
.name = "override_pause_level",
.section = "*",
.description = "TODO",
.type = TYPE_INT,
.default_value = "-1",
.value = NULL,
.parser = NULL,
.parser_data = NULL,
.rule_offset = offsetof(struct rule, override_pause_level),
},
// end of modifying rules

// other settings below
Expand Down
53 changes: 52 additions & 1 deletion test/dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ TEST test_dbus_cb_dunst_Properties_Get(void)
ASSERT_FALSE(g_variant_get_boolean(pause_variant));
g_variant_unref(pause_variant);

dunst_status(S_RUNNING, false);
dunst_status_int(S_PAUSE_LEVEL, 100);

pause_variant = dbus_cb_dunst_Properties_Get(connection_client,
FDN_NAME,
Expand Down Expand Up @@ -467,6 +467,56 @@ TEST test_dbus_cb_dunst_Properties_Set(void)
PASS();
}

TEST test_dbus_cb_dunst_Properties_Set_pause_level(void)
{

GDBusConnection *connection_client;
GError *error = NULL;
struct signal_propertieschanged sig = {NULL, NULL, NULL, -1};

dbus_signal_subscribe_propertieschanged(&sig);

connection_client = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);

GVariant *pause_variant = g_variant_new_uint32(33);


ASSERT(dbus_cb_dunst_Properties_Set(connection_client,
FDN_NAME,
FDN_PATH,
DUNST_IFAC,
"pauseLevel",
pause_variant,
&error,
NULL));

if (error) {
printf("Error while calling dbus_cb_dunst_Properties_Set: %s\n", error->message);
g_error_free(error);
}

uint waiting = 0;
while (!sig.interface && waiting < 2000) {
usleep(500);
waiting++;
}

ASSERT_STR_EQ(sig.interface, DUNST_IFAC);

guint pauseLevel;
g_variant_lookup(sig.array_dict_sv_data, "pauseLevel", "u", &pauseLevel);

ASSERT(pauseLevel == 33);

g_variant_unref(pause_variant);
g_free(sig.interface);
g_variant_unref(sig.array_dict_sv_data);
g_variant_unref(sig.array_s_data);
dbus_signal_unsubscribe_propertieschanged(&sig);
g_object_unref(connection_client);
PASS();
}

TEST test_empty_notification(void)
{
struct dbus_notification *n = dbus_notification_new();
Expand Down Expand Up @@ -1125,6 +1175,7 @@ gpointer run_threaded_tests(gpointer data)
RUN_TEST(test_get_fdn_daemon_info);
RUN_TEST(test_dbus_cb_dunst_Properties_Get);
RUN_TEST(test_dbus_cb_dunst_Properties_Set);
RUN_TEST(test_dbus_cb_dunst_Properties_Set_pause_level);

RUN_TEST(test_empty_notification);
RUN_TEST(test_basic_notification);
Expand Down
4 changes: 2 additions & 2 deletions test/dunst.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ TEST test_dunst_status(void)
ASSERT(status.fullscreen);
dunst_status(S_IDLE, true);
ASSERT(status.idle);
dunst_status(S_RUNNING, true);
ASSERT(status.running);
dunst_status_int(S_PAUSE_LEVEL, 0);
ASSERT(status.pause_level == 0);

PASS();
}
Expand Down
Loading