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-pause-level:Get current dunst's pause level'
'set-pause-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
10 changes: 10 additions & 0 deletions docs/dunst.5.pod
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,16 @@ Ignore the dbus closeNotification message. This is useful to enforce the timeout
set by dunst configuration. Without this parameter, an application may close
the notification sent before the user defined timeout.

=item B<override_pause_level> (values: [0-100], default: 0)

A Notification will appear whenever notification's
override_pause_level >= dunst's paused level. Setting this to values other than 0
allows you to create partial pause modes, where more urgent notifications get through,
but less urgent stay paused. For example, when you can set a low battery noficiation's
override_pause_level to 2 and then set dunst's pause level to 2. This will cause dunst to
fwsmit marked this conversation as resolved.
Show resolved Hide resolved
only show battery level notification (and other notifications with override_pause_level >= 2),
while suspending others.

=back

=head2 Keyboard shortcuts (X11 only)
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-pause-level Get the current pause level
set-pause-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-pause-level")
property_get pauseLevel | ( read -r _ _ paused; printf "%s\n" "${paused}"; )
;;
"set-pause-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
7 changes: 7 additions & 0 deletions dunstrc
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@
background = "#285577"
foreground = "#ffffff"
timeout = 10
override_pause_level = 30
# Icon for notifications with normal urgency, uncomment to enable
#default_icon = /path/to/icon

Expand All @@ -331,6 +332,7 @@
foreground = "#ffffff"
frame_color = "#ff0000"
timeout = 0
override_pause_level = 60
# Icon for notifications with critical urgency, uncomment to enable
#default_icon = /path/to/icon

Expand Down Expand Up @@ -368,13 +370,18 @@
# ellipsize
# alignment
# hide_text
# override_pause_level
#
# 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.
#
# You can also allow a 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. To do that, you can override the following in the rules:
# override_pause_level = X

# SCRIPTING
# You can specify a script that gets run when the rule matches by
# setting the "script" option.
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
Loading
Loading