Repository: qtile/qtile

Issue:
Battery low notifications go away with `dunst`
yesterday, thanks to @m-col, I manage to have beautiful popup notifications for my battery from within `qtile`'s bar and even sound and brightness bars as I change them with the keyboard:
![notifications dunst](https://user-images.githubusercontent.com/44101798/154742799-065fd65d-1499-45aa-ac37-a5b05bc23943.png)
However it is still not behaving quite as I expected.

I expected the notifications for a low battery to be of *urgent*/*critical* priority and it is red indeed.
I configured my [dunst](https://github.com/a2n-s/dotfiles/blob/main/.config/dunst/dunstrc#L292) so that *low* and *normal* notifications go away quite quicly, but *critical*/red ones never go away!

This is what I observe when I run either
```
notify-send "ERROR" "this is an error" -u critical
notify-send "NORMAL" "this is a normal message" -u normal
notify-send "LOW" "this is nothing important" -u low
```
or
```
dunstify "ERROR" "this is an error" -u critical
dunstify "NORMAL" "this is a normal message" -u normal
dunstify "LOW" "this is nothing important" -u low
```

But this is **not the case with the *critical* battery low notifications** from `qtile`.

I do not really understand the code of the `libqtile.widget.Battery` class, could anyone help fix that?


Discussion:
The widget should send an urgent notification so something's going wrong by the sounds of it. Let me take a look.
The widget does send messages marked as "urgent". However, I suspect your issue is that the notification is also sent with a set timeout (10 seconds) which dunst is, presumably, honouring.
> The widget does send messages marked as "urgent". However, I suspect your issue is that the notification is also sent with a set timeout (10 seconds) which dunst is, presumably, honouring.

oooh

it looks exactly the same as a *critical* issue thrown from `dunstify` or `notify-send` indeed!
A timeout is a good suspect :thinking:

But **is there a way to remove the timeout without modifying the source code?**
> But **is there a way to remove the timeout without modifying the source code?**

Sadly, no.

However... you might be able to get dunst to ignore it:
https://github.com/dunst-project/dunst/blob/ba4d9d5b9e9d6b761ddd08076031d643c0904666/dunstrc#L234-L238

It appears not to be working :thinking:
I did restart `dunst` after killing it and did make sure it was loaded with the new config file, i.e. `dunst -conf ~/.config/dunst/dunstrc`,
when running `dunstify "ERROR" "msg" -u critical`, it never goes away, but with `dunstify "ERROR" "msg" -u critical -t 1000`, it goes away after 1 sec!

So if the only solution is to fiddle with the source, **could a timeout argument for the `libqtile.widget.Battery` class be implemented?** Either by one of you guys or through a pull request?

It is not that big of an issue, but I think it would make *more sense for such important notifications to stick on the screen a bit longer!* :yum:

We could certainly add a timeout request to the notification. I can do a PR for that.

Resolving patch:
diff --git a/libqtile/widget/battery.py b/libqtile/widget/battery.py
--- a/libqtile/widget/battery.py
+++ b/libqtile/widget/battery.py
@@ -330,6 +330,7 @@ class Battery(base.ThreadPoolText):
         ("update_interval", 60, "Seconds between status updates"),
         ("battery", 0, "Which battery should be monitored (battery number or name)"),
         ("notify_below", None, "Send a notification below this battery level."),
+        ("notification_timeout", 10, "Time in seconds to display notification. 0 for no expiry."),
     ]
 
     def __init__(self, **config) -> None:
@@ -345,6 +346,7 @@ def __init__(self, **config) -> None:
 
         self._battery = self._load_battery(**config)
         self._has_notified = False
+        self.timeout = int(self.notification_timeout * 1000)
 
     def _configure(self, qtile, bar):
         if not self.low_background:
@@ -378,7 +380,12 @@ def poll(self) -> str:
             percent = int(status.percent * 100)
             if percent < self.notify_below:
                 if not self._has_notified:
-                    send_notification("Warning", "Battery at {0}%".format(percent), urgent=True)
+                    send_notification(
+                        "Warning",
+                        "Battery at {0}%".format(percent),
+                        urgent=True,
+                        timeout=self.timeout,
+                    )
                     self._has_notified = True
             elif self._has_notified:
                 self._has_notified = False


Test patch: