Repository: qtile/qtile

Issue:
Issue with icon pixmaps with (e.g) nm-applet in Wayland
### The issue:

Hi again,

To manage my wireless connections, I use nm-applet, blueman for bluetooth and redshift so my eyes don't give up on me by the time I'm 40.

These load their icons fine with the systray on X11, but on Wayland using either the qtile StatusNotifier or the qtile-extras StatusNotifier, I get the following error:

```
dbus_next.errors.InvalidBusNameError: invalid bus name: /org/ayatana/NotificationItem/blueman
2022-04-30 22:13:18,919 ERROR libqtile loop.py:_handle_exception():L63 'ProxyInterface' object has noattribute 'get_icon_pixmap'
Traceback (most recent call last):
  File "/usr/lib/python3.10/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/home/joao/.local/lib/python3.10/site-packages/libqtile/widget/statusnotifier.py", line 503, in item_added
    success = future.result()
  File "/home/joao/.local/lib/python3.10/site-packages/libqtile/widget/statusnotifier.py", line 155, in start
    await self._get_icon(icon)
  File "/home/joao/.local/lib/python3.10/site-packages/libqtile/widget/statusnotifier.py", line 206, in _get_icon
    pixmap = getattr(self.item, method)
AttributeError: 'ProxyInterface' object has no attribute 'get_icon_pixmap'
```

This happens for blueman (as seen above), nm-applet and redshift. 

The weird part is that Protonmail Bridge's applet appears fine (in fact, it appears twice). 

I am using the latest qtile dev version straight from github.

### Required:

- [X] I have searched past issues to see if this bug has already been reported.


Discussion:
Thanks for the report. I'll take a look.

FYI - the qtile-extras StatusNotifier just adds the context menus to the qtile widget.
Ok. So this is an issue with Ayatana apps moving away from the StatusNotifierItem spec. The app does not provide an icon over the dbus interface and so our attempt to look it up fails.

However, this lookup is only needed if we can't find the correct icon in your installed icons. Make sure you've got `xdg` installed.

I'll add some error handling to catch the errors you're seeing.
Ah makes sense, it seems like it's a problem with Ayatana apps.

However, I do have xdg installed and tried to the default adwaita icons, but the error still persists. Weird.
`blueman-applet` succesfully displays icons for me. Let me debug where I'm pulling my icons from.

Oh, and also, the `InvalidBusName` error at the top of your log will be fixed by #3449,
> Ah makes sense, it seems like it's a problem with Ayatana apps.

The problem is more to do with my implementation of the code! I followed the original StatusNotifierItem specification. I didn't realise Ayatana did something different so I've had to hack my code to make it work as best I can.
So, for me, the icons are found via xdg. Do you know if the right icons are even installed?

Resolving patch:
diff --git a/libqtile/widget/statusnotifier.py b/libqtile/widget/statusnotifier.py
--- a/libqtile/widget/statusnotifier.py
+++ b/libqtile/widget/statusnotifier.py
@@ -154,14 +154,15 @@ async def start(self):
             for icon in ["Icon", "Attention", "Overlay"]:
                 await self._get_icon(icon)
 
-            # Attach listeners for when the icon is updated
-            self.item.on_new_icon(self._new_icon)
-            self.item.on_new_attention_icon(self._new_attention_icon)
-            self.item.on_new_overlay_icon(self._new_overlay_icon)
+            if self.has_icons:
+                # Attach listeners for when the icon is updated
+                self.item.on_new_icon(self._new_icon)
+                self.item.on_new_attention_icon(self._new_attention_icon)
+                self.item.on_new_overlay_icon(self._new_overlay_icon)
 
         if not self.has_icons:
             logger.warning(
-                "Cannot find icon in current theme and " "no icon provided by StatusNotifierItem."
+                "Cannot find icon in current theme and no icon provided by StatusNotifierItem."
             )
 
         return True
@@ -203,7 +204,9 @@ async def _get_icon(self, icon_name):
         adds to an internal dictionary for later retrieval.
         """
         attr, method = self.icon_map[icon_name]
-        pixmap = getattr(self.item, method)
+        pixmap = getattr(self.item, method, None)
+        if pixmap is None:
+            return
         icon_pixmap = await pixmap()
 
         # Items can present multiple pixmaps for different


Test patch: