We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
App crashes when sending a dbus notification
### The issue:

See https://github.com/ciderapp/Cider/issues/1475 for more details. 

After playing a few songs with Cider App, the app will crash when changing songs with the following error message in the logs. I am not sure which side is responsible for the bug. 

```
[395803:0929/171008.500207:ERROR:libnotify_notification.cc(49)] notify_notification_close: domain=1236 code=36 message="GDBus.Error:com.dubstepdish.dbus.next.ServiceError: The service interface raised an error: list index out of range.
['  File "/usr/lib/python3.10/site-packages/dbus_next/message_bus.py", line 712, in _process_message\n    handler(msg, send_reply)\n', '  File "/usr/lib/python3.10/site-packages/dbus_next/message_bus.py", line 731, in handler\n    result = method.fn(interface, *args)\n', '  File "/usr/lib/python3.10/site-packages/libqtile/notify.py", line 88, in CloseNotification\n    self.manager.close(nid)\n', '  File "/usr/lib/python3.10/site-packages/libqtile/notify.py", line 203, in close\n    notif = self.notifications[nid]\n']"
Trace/breakpoint trap (core dumped)
```

### Required:

- [X] I have searched past issues to see if this bug has already been reported.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `libqtile/notify.py`
Content:
```
1 # Copyright (c) 2010 dequis
2 # Copyright (c) 2011 Florian Mounier
3 # Copyright (c) 2011 Mounier Florian
4 # Copyright (c) 2013 Mickael FALCK
5 # Copyright (c) 2013 Tao Sauvage
6 # Copyright (c) 2020 elParaguayo
7 #
8 # Permission is hereby granted, free of charge, to any person obtaining a copy
9 # of this software and associated documentation files (the "Software"), to deal
10 # in the Software without restriction, including without limitation the rights
11 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 # copies of the Software, and to permit persons to whom the Software is
13 # furnished to do so, subject to the following conditions:
14 #
15 # The above copyright notice and this permission notice shall be included in
16 # all copies or substantial portions of the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 # SOFTWARE.
25 import asyncio
26 from typing import Any
27 
28 try:
29     from dbus_next import ReleaseNameReply
30     from dbus_next.aio import MessageBus
31     from dbus_next.service import ServiceInterface, method, signal
32 
33     has_dbus = True
34 except ImportError:
35     has_dbus = False
36 
37 from libqtile.log_utils import logger
38 
39 BUS_NAME = "org.freedesktop.Notifications"
40 SERVICE_PATH = "/org/freedesktop/Notifications"
41 
42 notifier: Any = None
43 
44 
45 class ClosedReason:
46     expired = 1
47     dismissed = 2
48     method = 3  # CloseNotification method
49 
50 
51 if has_dbus:
52 
53     class NotificationService(ServiceInterface):
54         def __init__(self, manager):
55             super().__init__(BUS_NAME)
56             self.manager = manager
57             self._capabilities = {"body"}
58 
59         @method()
60         def GetCapabilities(self) -> "as":  # type:ignore  # noqa: N802, F722
61             return list(self._capabilities)
62 
63         def register_capabilities(self, capabilities):
64             if isinstance(capabilities, str):
65                 self._capabilities.add(capabilities)
66             elif isinstance(capabilities, (tuple, list, set)):
67                 self._capabilities.update(set(capabilities))
68 
69         @method()
70         def Notify(  # noqa: N802, F722
71             self,
72             app_name: "s",  # type:ignore  # noqa: F821
73             replaces_id: "u",  # type:ignore  # noqa: F821
74             app_icon: "s",  # type:ignore  # noqa: F821
75             summary: "s",  # type:ignore  # noqa: F821
76             body: "s",  # type:ignore  # noqa: F821
77             actions: "as",  # type:ignore  # noqa: F821
78             hints: "a{sv}",  # type:ignore  # noqa: F821
79             timeout: "i",  # type:ignore  # noqa: F821
80         ) -> "u":  # type:ignore  # noqa: F821
81             notif = Notification(
82                 summary, body, timeout, hints, app_name, replaces_id, app_icon, actions
83             )
84             return self.manager.add(notif)
85 
86         @method()
87         def CloseNotification(self, nid: "u"):  # type:ignore  # noqa: N802, F821
88             self.manager.close(nid)
89 
90         @signal()
91         def NotificationClosed(  # noqa: N802
92             self, nid: "u", reason: "u"  # type: ignore  # noqa: F821
93         ) -> "uu":  # type: ignore  # noqa: F821
94             return [nid, reason]
95 
96         @signal()
97         def ActionInvoked(  # noqa: N802
98             self, nid: "u", action_key: "s"  # type: ignore  # noqa: F821
99         ) -> "us":  # type:ignore  # noqa: N802, F821
100             return [nid, action_key]
101 
102         @method()
103         def GetServerInformation(self) -> "ssss":  # type: ignore  # noqa: N802, F821
104             return ["qtile-notify-daemon", "qtile", "1.0", "1"]
105 
106     class Notification:
107         def __init__(
108             self,
109             summary,
110             body="",
111             timeout=-1,
112             hints=None,
113             app_name="",
114             replaces_id=None,
115             app_icon=None,
116             actions=None,
117         ):
118             self.summary = summary
119             self.body = body
120             self.timeout = timeout
121             self.hints = hints or {}
122             self.app_name = app_name
123             self.replaces_id = replaces_id
124             self.app_icon = app_icon
125             self.actions = actions
126 
127     class NotificationManager:
128         def __init__(self):
129             self.notifications = []
130             self.callbacks = []
131             self.close_callbacks = []
132             self._service = None
133 
134         async def service(self):
135             if self._service is None:
136                 try:
137                     self.bus = await MessageBus().connect()
138                     self._service = NotificationService(self)
139                     self.bus.export(SERVICE_PATH, self._service)
140                     await self.bus.request_name(BUS_NAME)
141                 except Exception:
142                     logger.exception("Dbus connection failed")
143                     self._service = None
144             return self._service
145 
146         async def register(self, callback, capabilities=None, on_close=None):
147             service = await self.service()
148             if not service:
149                 logger.warning(
150                     "Registering %s without any dbus connection existing",
151                     callback.__name__,
152                 )
153             self.callbacks.append(callback)
154             if capabilities:
155                 self._service.register_capabilities(capabilities)
156             if on_close:
157                 self.close_callbacks.append(on_close)
158 
159         def unregister(self, callback, on_close=None):
160             try:
161                 self.callbacks.remove(callback)
162             except ValueError:
163                 logger.error("Unable to remove notify callback. Unknown callback.")
164 
165             if on_close:
166                 try:
167                     self.close_callbacks.remove(on_close)
168                 except ValueError:
169                     logger.error("Unable to remove notify on_close callback. Unknown callback.")
170 
171             if not self.callbacks:
172                 return asyncio.create_task(self._release())
173 
174         async def _release(self):
175             """
176             If the manager has no more callbacks then we need to release the service name
177             from dbus and reset _service to None (to force subsequent calls to `register` to
178             re-register the name on dbus.)
179             """
180             reply = await self.bus.release_name(BUS_NAME)
181 
182             if reply != ReleaseNameReply.RELEASED:
183                 logger.error("Could not release %s", BUS_NAME)
184                 return
185 
186             self._service = None
187 
188         def add(self, notif):
189             self.notifications.append(notif)
190             notif.id = len(self.notifications)
191             for callback in self.callbacks:
192                 try:
193                     callback(notif)
194                 except Exception:
195                     logger.exception("Exception in notifier callback")
196             return len(self.notifications)
197 
198         def show(self, *args, **kwargs):
199             notif = Notification(*args, **kwargs)
200             return (notif, self.add(notif))
201 
202         def close(self, nid):
203             notif = self.notifications[nid]
204 
205             for callback in self.close_callbacks:
206                 try:
207                     callback(notif)
208                 except Exception:
209                     logger.exception("Exception in notifier close callback")
210 
211     notifier = NotificationManager()
212
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/libqtile/notify.py b/libqtile/notify.py
--- a/libqtile/notify.py
+++ b/libqtile/notify.py
@@ -200,11 +200,9 @@
             return (notif, self.add(notif))
 
         def close(self, nid):
-            notif = self.notifications[nid]
-
             for callback in self.close_callbacks:
                 try:
-                    callback(notif)
+                    callback(nid)
                 except Exception:
                     logger.exception("Exception in notifier close callback")

{"golden_diff": "diff --git a/libqtile/notify.py b/libqtile/notify.py\n--- a/libqtile/notify.py\n+++ b/libqtile/notify.py\n@@ -200,11 +200,9 @@\n             return (notif, self.add(notif))\n \n         def close(self, nid):\n-            notif = self.notifications[nid]\n-\n             for callback in self.close_callbacks:\n                 try:\n-                    callback(notif)\n+                    callback(nid)\n                 except Exception:\n                     logger.exception(\"Exception in notifier close callback\")\n", "issue": "App crashes when sending a dbus notification\n### The issue:\n\nSee https://github.com/ciderapp/Cider/issues/1475 for more details. \r\n\r\nAfter playing a few songs with Cider App, the app will crash when changing songs with the following error message in the logs. I am not sure which side is responsible for the bug. \r\n\r\n```\r\n[395803:0929/171008.500207:ERROR:libnotify_notification.cc(49)] notify_notification_close: domain=1236 code=36 message=\"GDBus.Error:com.dubstepdish.dbus.next.ServiceError: The service interface raised an error: list index out of range.\r\n['  File \"/usr/lib/python3.10/site-packages/dbus_next/message_bus.py\", line 712, in _process_message\\n    handler(msg, send_reply)\\n', '  File \"/usr/lib/python3.10/site-packages/dbus_next/message_bus.py\", line 731, in handler\\n    result = method.fn(interface, *args)\\n', '  File \"/usr/lib/python3.10/site-packages/libqtile/notify.py\", line 88, in CloseNotification\\n    self.manager.close(nid)\\n', '  File \"/usr/lib/python3.10/site-packages/libqtile/notify.py\", line 203, in close\\n    notif = self.notifications[nid]\\n']\"\r\nTrace/breakpoint trap (core dumped)\r\n```\n\n### Required:\n\n- [X] I have searched past issues to see if this bug has already been reported.\n", "before_files": [{"content": "# Copyright (c) 2010 dequis\n# Copyright (c) 2011 Florian Mounier\n# Copyright (c) 2011 Mounier Florian\n# Copyright (c) 2013 Mickael FALCK\n# Copyright (c) 2013 Tao Sauvage\n# Copyright (c) 2020 elParaguayo\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\nimport asyncio\nfrom typing import Any\n\ntry:\n    from dbus_next import ReleaseNameReply\n    from dbus_next.aio import MessageBus\n    from dbus_next.service import ServiceInterface, method, signal\n\n    has_dbus = True\nexcept ImportError:\n    has_dbus = False\n\nfrom libqtile.log_utils import logger\n\nBUS_NAME = \"org.freedesktop.Notifications\"\nSERVICE_PATH = \"/org/freedesktop/Notifications\"\n\nnotifier: Any = None\n\n\nclass ClosedReason:\n    expired = 1\n    dismissed = 2\n    method = 3  # CloseNotification method\n\n\nif has_dbus:\n\n    class NotificationService(ServiceInterface):\n        def __init__(self, manager):\n            super().__init__(BUS_NAME)\n            self.manager = manager\n            self._capabilities = {\"body\"}\n\n        @method()\n        def GetCapabilities(self) -> \"as\":  # type:ignore  # noqa: N802, F722\n            return list(self._capabilities)\n\n        def register_capabilities(self, capabilities):\n            if isinstance(capabilities, str):\n                self._capabilities.add(capabilities)\n            elif isinstance(capabilities, (tuple, list, set)):\n                self._capabilities.update(set(capabilities))\n\n        @method()\n        def Notify(  # noqa: N802, F722\n            self,\n            app_name: \"s\",  # type:ignore  # noqa: F821\n            replaces_id: \"u\",  # type:ignore  # noqa: F821\n            app_icon: \"s\",  # type:ignore  # noqa: F821\n            summary: \"s\",  # type:ignore  # noqa: F821\n            body: \"s\",  # type:ignore  # noqa: F821\n            actions: \"as\",  # type:ignore  # noqa: F821\n            hints: \"a{sv}\",  # type:ignore  # noqa: F821\n            timeout: \"i\",  # type:ignore  # noqa: F821\n        ) -> \"u\":  # type:ignore  # noqa: F821\n            notif = Notification(\n                summary, body, timeout, hints, app_name, replaces_id, app_icon, actions\n            )\n            return self.manager.add(notif)\n\n        @method()\n        def CloseNotification(self, nid: \"u\"):  # type:ignore  # noqa: N802, F821\n            self.manager.close(nid)\n\n        @signal()\n        def NotificationClosed(  # noqa: N802\n            self, nid: \"u\", reason: \"u\"  # type: ignore  # noqa: F821\n        ) -> \"uu\":  # type: ignore  # noqa: F821\n            return [nid, reason]\n\n        @signal()\n        def ActionInvoked(  # noqa: N802\n            self, nid: \"u\", action_key: \"s\"  # type: ignore  # noqa: F821\n        ) -> \"us\":  # type:ignore  # noqa: N802, F821\n            return [nid, action_key]\n\n        @method()\n        def GetServerInformation(self) -> \"ssss\":  # type: ignore  # noqa: N802, F821\n            return [\"qtile-notify-daemon\", \"qtile\", \"1.0\", \"1\"]\n\n    class Notification:\n        def __init__(\n            self,\n            summary,\n            body=\"\",\n            timeout=-1,\n            hints=None,\n            app_name=\"\",\n            replaces_id=None,\n            app_icon=None,\n            actions=None,\n        ):\n            self.summary = summary\n            self.body = body\n            self.timeout = timeout\n            self.hints = hints or {}\n            self.app_name = app_name\n            self.replaces_id = replaces_id\n            self.app_icon = app_icon\n            self.actions = actions\n\n    class NotificationManager:\n        def __init__(self):\n            self.notifications = []\n            self.callbacks = []\n            self.close_callbacks = []\n            self._service = None\n\n        async def service(self):\n            if self._service is None:\n                try:\n                    self.bus = await MessageBus().connect()\n                    self._service = NotificationService(self)\n                    self.bus.export(SERVICE_PATH, self._service)\n                    await self.bus.request_name(BUS_NAME)\n                except Exception:\n                    logger.exception(\"Dbus connection failed\")\n                    self._service = None\n            return self._service\n\n        async def register(self, callback, capabilities=None, on_close=None):\n            service = await self.service()\n            if not service:\n                logger.warning(\n                    \"Registering %s without any dbus connection existing\",\n                    callback.__name__,\n                )\n            self.callbacks.append(callback)\n            if capabilities:\n                self._service.register_capabilities(capabilities)\n            if on_close:\n                self.close_callbacks.append(on_close)\n\n        def unregister(self, callback, on_close=None):\n            try:\n                self.callbacks.remove(callback)\n            except ValueError:\n                logger.error(\"Unable to remove notify callback. Unknown callback.\")\n\n            if on_close:\n                try:\n                    self.close_callbacks.remove(on_close)\n                except ValueError:\n                    logger.error(\"Unable to remove notify on_close callback. Unknown callback.\")\n\n            if not self.callbacks:\n                return asyncio.create_task(self._release())\n\n        async def _release(self):\n            \"\"\"\n            If the manager has no more callbacks then we need to release the service name\n            from dbus and reset _service to None (to force subsequent calls to `register` to\n            re-register the name on dbus.)\n            \"\"\"\n            reply = await self.bus.release_name(BUS_NAME)\n\n            if reply != ReleaseNameReply.RELEASED:\n                logger.error(\"Could not release %s\", BUS_NAME)\n                return\n\n            self._service = None\n\n        def add(self, notif):\n            self.notifications.append(notif)\n            notif.id = len(self.notifications)\n            for callback in self.callbacks:\n                try:\n                    callback(notif)\n                except Exception:\n                    logger.exception(\"Exception in notifier callback\")\n            return len(self.notifications)\n\n        def show(self, *args, **kwargs):\n            notif = Notification(*args, **kwargs)\n            return (notif, self.add(notif))\n\n        def close(self, nid):\n            notif = self.notifications[nid]\n\n            for callback in self.close_callbacks:\n                try:\n                    callback(notif)\n                except Exception:\n                    logger.exception(\"Exception in notifier close callback\")\n\n    notifier = NotificationManager()\n", "path": "libqtile/notify.py"}], "after_files": [{"content": "# Copyright (c) 2010 dequis\n# Copyright (c) 2011 Florian Mounier\n# Copyright (c) 2011 Mounier Florian\n# Copyright (c) 2013 Mickael FALCK\n# Copyright (c) 2013 Tao Sauvage\n# Copyright (c) 2020 elParaguayo\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\nimport asyncio\nfrom typing import Any\n\ntry:\n    from dbus_next import ReleaseNameReply\n    from dbus_next.aio import MessageBus\n    from dbus_next.service import ServiceInterface, method, signal\n\n    has_dbus = True\nexcept ImportError:\n    has_dbus = False\n\nfrom libqtile.log_utils import logger\n\nBUS_NAME = \"org.freedesktop.Notifications\"\nSERVICE_PATH = \"/org/freedesktop/Notifications\"\n\nnotifier: Any = None\n\n\nclass ClosedReason:\n    expired = 1\n    dismissed = 2\n    method = 3  # CloseNotification method\n\n\nif has_dbus:\n\n    class NotificationService(ServiceInterface):\n        def __init__(self, manager):\n            super().__init__(BUS_NAME)\n            self.manager = manager\n            self._capabilities = {\"body\"}\n\n        @method()\n        def GetCapabilities(self) -> \"as\":  # type:ignore  # noqa: N802, F722\n            return list(self._capabilities)\n\n        def register_capabilities(self, capabilities):\n            if isinstance(capabilities, str):\n                self._capabilities.add(capabilities)\n            elif isinstance(capabilities, (tuple, list, set)):\n                self._capabilities.update(set(capabilities))\n\n        @method()\n        def Notify(  # noqa: N802, F722\n            self,\n            app_name: \"s\",  # type:ignore  # noqa: F821\n            replaces_id: \"u\",  # type:ignore  # noqa: F821\n            app_icon: \"s\",  # type:ignore  # noqa: F821\n            summary: \"s\",  # type:ignore  # noqa: F821\n            body: \"s\",  # type:ignore  # noqa: F821\n            actions: \"as\",  # type:ignore  # noqa: F821\n            hints: \"a{sv}\",  # type:ignore  # noqa: F821\n            timeout: \"i\",  # type:ignore  # noqa: F821\n        ) -> \"u\":  # type:ignore  # noqa: F821\n            notif = Notification(\n                summary, body, timeout, hints, app_name, replaces_id, app_icon, actions\n            )\n            return self.manager.add(notif)\n\n        @method()\n        def CloseNotification(self, nid: \"u\"):  # type:ignore  # noqa: N802, F821\n            self.manager.close(nid)\n\n        @signal()\n        def NotificationClosed(  # noqa: N802\n            self, nid: \"u\", reason: \"u\"  # type: ignore  # noqa: F821\n        ) -> \"uu\":  # type: ignore  # noqa: F821\n            return [nid, reason]\n\n        @signal()\n        def ActionInvoked(  # noqa: N802\n            self, nid: \"u\", action_key: \"s\"  # type: ignore  # noqa: F821\n        ) -> \"us\":  # type:ignore  # noqa: N802, F821\n            return [nid, action_key]\n\n        @method()\n        def GetServerInformation(self) -> \"ssss\":  # type: ignore  # noqa: N802, F821\n            return [\"qtile-notify-daemon\", \"qtile\", \"1.0\", \"1\"]\n\n    class Notification:\n        def __init__(\n            self,\n            summary,\n            body=\"\",\n            timeout=-1,\n            hints=None,\n            app_name=\"\",\n            replaces_id=None,\n            app_icon=None,\n            actions=None,\n        ):\n            self.summary = summary\n            self.body = body\n            self.timeout = timeout\n            self.hints = hints or {}\n            self.app_name = app_name\n            self.replaces_id = replaces_id\n            self.app_icon = app_icon\n            self.actions = actions\n\n    class NotificationManager:\n        def __init__(self):\n            self.notifications = []\n            self.callbacks = []\n            self.close_callbacks = []\n            self._service = None\n\n        async def service(self):\n            if self._service is None:\n                try:\n                    self.bus = await MessageBus().connect()\n                    self._service = NotificationService(self)\n                    self.bus.export(SERVICE_PATH, self._service)\n                    await self.bus.request_name(BUS_NAME)\n                except Exception:\n                    logger.exception(\"Dbus connection failed\")\n                    self._service = None\n            return self._service\n\n        async def register(self, callback, capabilities=None, on_close=None):\n            service = await self.service()\n            if not service:\n                logger.warning(\n                    \"Registering %s without any dbus connection existing\",\n                    callback.__name__,\n                )\n            self.callbacks.append(callback)\n            if capabilities:\n                self._service.register_capabilities(capabilities)\n            if on_close:\n                self.close_callbacks.append(on_close)\n\n        def unregister(self, callback, on_close=None):\n            try:\n                self.callbacks.remove(callback)\n            except ValueError:\n                logger.error(\"Unable to remove notify callback. Unknown callback.\")\n\n            if on_close:\n                try:\n                    self.close_callbacks.remove(on_close)\n                except ValueError:\n                    logger.error(\"Unable to remove notify on_close callback. Unknown callback.\")\n\n            if not self.callbacks:\n                return asyncio.create_task(self._release())\n\n        async def _release(self):\n            \"\"\"\n            If the manager has no more callbacks then we need to release the service name\n            from dbus and reset _service to None (to force subsequent calls to `register` to\n            re-register the name on dbus.)\n            \"\"\"\n            reply = await self.bus.release_name(BUS_NAME)\n\n            if reply != ReleaseNameReply.RELEASED:\n                logger.error(\"Could not release %s\", BUS_NAME)\n                return\n\n            self._service = None\n\n        def add(self, notif):\n            self.notifications.append(notif)\n            notif.id = len(self.notifications)\n            for callback in self.callbacks:\n                try:\n                    callback(notif)\n                except Exception:\n                    logger.exception(\"Exception in notifier callback\")\n            return len(self.notifications)\n\n        def show(self, *args, **kwargs):\n            notif = Notification(*args, **kwargs)\n            return (notif, self.add(notif))\n\n        def close(self, nid):\n            for callback in self.close_callbacks:\n                try:\n                    callback(nid)\n                except Exception:\n                    logger.exception(\"Exception in notifier close callback\")\n\n    notifier = NotificationManager()\n", "path": "libqtile/notify.py"}]}