Repository: qtile/qtile

Issue:
WidgetBox does not fully re-expand on click
# Issue description

On first click, WidgetBox expands properly, but clicking a second time does not hide all widgets.

Specifically, in my configuration (below), the Wallpaper is shown/hidden properly, but the Systray does not hide again.

# Qtile version

qtile-0.17.1.dev82+geb8722ec

# Stack traces

no errors in qtile.log

# Configuration

```
            widget.WidgetBox(widgets=[
                widget.Wallpaper(directory='~/Downloads/wallpaper/', wallpaper_command=None, random_selection=True, label='\u0394'),
                widget.Systray(padding=1, icon_size=22),
                ], close_button_location='right',
            ),
```




Discussion:
Thanks knodalyte. This widget was mine so let me take a look. 

I didn't test with systray as I don't use it. My understanding is that that widget is a little bit different to the others so it may be the case that it would need some additional logic to handle it.
Just tested this. Pretty sure this is specific to systray.

Widgetbox is correctly adding and removing the widgets when it's opened and closed. However, systray seems to generate a widget and a window and I suspect it's the latter that causes the issue here. I'll do some digging to see if there's a way to hide the systray but my optimistic quick fix failed!
Inspired from the systray.draw method, the icons of the systray could be hidden by a new method of Systray class like this :
```
    def hide_icons(self):
        for pos, icon in enumerate(self.icons.values()):
            icon.hide()
```
            
Then a call of this new method at the beginning of the draw method of WidgetBox class if :
		- the systray widget is present in the widgetbox,
		- and the widgetbox is not open
may be another optimistic quick fix :)
Yes, I hadn't appreciated that the icons were also windows so they'll need to be hidden separately too.
OK. Think I've got it working.

Systray's draw method unhides the icons if they're hidden but as the draw method isn't called for widgets that are in the box then that doesn't matter so all we need to do is hide the icons when closing the box.

It feels very hacky to do this but Systray does seem to be a special case of widget.

I'll do a bit more testing and then submit a PR.

Resolving patch:
diff --git a/libqtile/widget/widgetbox.py b/libqtile/widget/widgetbox.py
--- a/libqtile/widget/widgetbox.py
+++ b/libqtile/widget/widgetbox.py
@@ -22,7 +22,7 @@
 
 from libqtile import bar
 from libqtile.log_utils import logger
-from libqtile.widget import base
+from libqtile.widget import Systray, base
 
 BoxedWidget = namedtuple("BoxedWidget", ["widget", "draw"])
 
@@ -152,6 +152,14 @@ def toggle_widgets(self):
                 self.bar.widgets.remove(item.widget)
                 # Override drawer.drawer with a no-op
                 item.widget.drawer.draw = _no_draw
+
+                # Systray widget needs some additional steps to hide as the icons
+                # are separate _Window instances.
+                # Systray unhides icons when it draws so we only need to hide them.
+                if isinstance(item.widget, Systray):
+                    for icon in item.widget.icons.values():
+                        icon.hide()
+
             except ValueError:
                 continue
 


Test patch: