Repository: qtile/qtile

Issue:
notify-send stops working when Qtile config is reload instead restart, or if widget.Notify is disabled
### The issue:

notify-send does not work anymore if Qtile config is reload, until I restart Qtile. It also will not work anymore and wait if I disable the "widget.Notify". I am not 100% sure if this is a problem caused by Qtile.

1. Whenever I reload Qtile config instead of restarting, the next run of the program `notify-send` will hang and wait. I have to Ctrl+c to end the process. When I then restart Qtile, then the program `notify-send` works as expected.
2. And i just tested to disable the widget.Notify and try again. Now The program always hangs, reload or not. `notify-send` seems not to find anything to send to. When I enable the widget, then it works like described at point 1.

Some system information:

- Your Qtile version (qtile --version): `0.21.1.dev8+gea4462b0`
- Relevant logs from ~/.local/share/qtile/qtile.log: 
`2022-04-05 21:48:41,482 ERROR libqtile notify.py:_release():L183 Could not release org.freedesktop.Notifications.`

```
OS: Manjaro Linux [x86_64]
Kernel: 5.16.14-1-MANJARO
Uptime: 1 day, 17 hours, 36 mins
Packages: 1896 (pacman)[stable], 1 (flatpak)
Shell: zsh 5.8.1
Resolution: 2560x1440 @ 144Hz
DE: KDE Plasma 5.24.3
WM: Qtile 0.21.1.dev8+gea4462b0
Theme: breeze (GruvboxColors) [Plasma], Klaus [GTK2/3/4]
Icons: breeze [Plasma], Gruvbox [GTK2/3/4]
Font: Noto Sans (12pt) [Plasma], Noto Sans (12pt) [GTK2/3/4]
Cursor: default (24px)
Terminal: kitty
CPU: Intel Xeon E3-1230 v3 (8) @ 3.7GHz
GPU: Nvidia GeForce GTX 1070
Memory: 3225MiB / 15947MiB (20%)
Disk (/): 98GB / 219GB (44%)
Locale: de_DE.UTF-8
```

### Required:

- [X] I have searched past issues to see if this bug has already been reported.


Discussion:
Thanks for the report. I've got some ideas as to what could be causing this. Let me investigate when I get a chance.
OK. This is something I wasn't expecting. The widget deregisters the notification service when it's finalised (which happens when the config is reloaded) but this deregistration finishes after the config has loaded so there's no notification server available.
Looking at the code, is it an async problem then? So the process is working in the background, while Qtile reloaded right?
Yeah - I need the finalize function to block until it's complete.

Resolving patch:
diff --git a/libqtile/widget/notify.py b/libqtile/widget/notify.py
--- a/libqtile/widget/notify.py
+++ b/libqtile/widget/notify.py
@@ -26,7 +26,6 @@
 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
-import asyncio
 from os import path
 
 from libqtile import bar, pangocffi, utils
@@ -89,6 +88,7 @@ def _configure(self, qtile, bar):
         )
 
     async def _config_async(self):
+        logger.debug("Registering notify widget")
         await notifier.register(self.update, self.capabilities, on_close=self.on_close)
 
     def set_notif_text(self, notif):
@@ -191,7 +191,14 @@ def cmd_invoke(self):
             self.invoke()
 
     def finalize(self):
-        asyncio.create_task(self._finalize())
+        # We may need some async calls as part of the finalize call
+        # We run this with `call_soon_threadsafe` as this waits for
+        # the job to finish before continuing. This is important as,
+        # if the config is just reloading, we need to finish deregistering
+        # the notification server before the new Notify widget instance
+        # registers and creates a new server.
+        self.qtile.call_soon_threadsafe(self._finalize)
+        base._TextBox.finalize(self)
 
     async def _finalize(self):
         task = notifier.unregister(self.update)
@@ -202,4 +209,3 @@ async def _finalize(self):
         # complete the finalisation of this widget.
         if task:
             await task
-        base._TextBox.finalize(self)


Test patch: