Repository: qtile/qtile

Issue:
widget.box does not close
Hi,

  I'm running qtile on arch and after the latest update the widget.box does not close.  It was working fine before the update.  

![qtilewidgetbox1](https://user-images.githubusercontent.com/10890303/150229622-6b4c0742-317b-42f5-829c-82cf3d2ce4c2.png)

![qtilewidgetbox2](https://user-images.githubusercontent.com/10890303/150229671-4abc6d90-8bda-438f-8c36-bdd1d0432fa6.png)
 


Discussion:
Hi there! That's an odd bug. Do you see anything being output into the log when you try to close it? The log is at `~/.local/share/qtile/qtile.log`.
Hey, I've checked the log and it is giving an error:

'2022-01-19 18:15:54,433 ERROR libqtile group.py:layout():L120 No such layout: MonadTall
2022-01-19 18:15:54,439 ERROR libqtile group.py:layout():L120 No such layout: MonadTall
2022-01-19 18:15:54,441 ERROR libqtile group.py:layout():L120 No such layout: MonadTall
2022-01-19 18:15:54,443 ERROR libqtile group.py:layout():L120 No such layout: MonadTall'

This happens on both of my machines with the same version of qtile.  It also happens with different layouts.  Also, I can force the widget.box closed by using Super + CTRL + r --which I'm guesing redraws the bar. 
When you're trying to close it, are you clicking on it or using a keybinding?

Please could you post your config
Possibly related: my `Mpd2` widget recently stopped responding to clicks too.
I'm clicking on it.  Here is my config:

```
# Copyright (c) 2010 Aldo Cortesi
# Copyright (c) 2010, 2014 dequis
# Copyright (c) 2012 Randall Ma
# Copyright (c) 2012-2014 Tycho Andersen
# Copyright (c) 2012 Craig Barnes
# Copyright (c) 2013 horsik
# Copyright (c) 2013 Tao Sauvage
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# 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.

from typing import List  # noqa: F401
from libqtile import bar, layout, widget, hook, qtile
from libqtile.config import Click, Drag, Group, Key, Match, Screen
from libqtile.lazy import lazy
from libqtile.utils import guess_terminal
from libqtile.log_utils import logger
from libqtile.dgroups import simple_key_binder
from libqtile.layout.base import _SimpleLayoutBase
import os
import subprocess
import owm

mod = "mod4"
terminal = "alacritty"
#home = os.path.expanduser('~')

keys = [
    # Switch between windows
    Key([mod], "h", lazy.layout.left(), desc="Move focus to left"),
    Key([mod], "l", lazy.layout.right(), desc="Move focus to right"),
    Key([mod], "j", lazy.layout.down(), desc="Move focus down"),
    Key([mod], "k", lazy.layout.up(), desc="Move focus up"),
    Key([mod], "space", lazy.layout.next(),
        desc="Move window focus to other window"),

    # Move windows between left/right columns or move up/down in current stack.
    # Moving out of range in Columns layout will create new column.
    Key([mod, "shift"], "h", lazy.layout.swap_left(),
        desc="swap window to the left"),
    Key([mod, "shift"], "l", lazy.layout.swap_right(),
        desc="swap window to the right"),
    Key([mod, "shift"], "j", lazy.layout.shuffle_down(),
        desc="Move window down"),
    Key([mod, "shift"], "k", lazy.layout.shuffle_up(), desc="Move window up"),

    # Grow windows. If current window is on the edge of screen and direction
    # will be to screen edge - window would shrink.
    Key([mod, "control"], "h", lazy.layout.grow_left(),
        desc="Grow window to the left"),
    Key([mod, "control"], "l", lazy.layout.grow_right(),
        desc="Grow window to the right"),
    Key([mod, "control"], "j", lazy.layout.grow_down(),
        desc="Grow window down"),
    Key([mod, "control"], "k", lazy.layout.grow_up(), desc="Grow window up"),
    Key([mod], "n", lazy.layout.normalize(), desc="Reset all window sizes"),
    Key([mod, "control"], "i", lazy.layout.grow(),
        desc="Grow"),
     Key([mod, "control"], "o", lazy.layout.shrink(),
        desc="Grow"),

    # Toggle between split and unsplit sides of stack.
    # Split = all windows displayed
    # Unsplit = 1 window displayed, like Max layout, but still with
    # multiple stack panes
    Key([mod, "shift"], "Return", lazy.layout.toggle_split(),
        desc="Toggle between split and unsplit sides of stack"),
    Key([mod], "Return", lazy.spawn(terminal), desc="Launch terminal"),

    # Toggle between different layouts as defined below
    Key([mod], "Tab", lazy.next_layout(), desc="Toggle between layouts"),
    Key([mod], "q", lazy.window.kill(), desc="Kill focused window"),
    Key([mod, "control"], "r", lazy.reload_config(), desc="Reload the config"),
    Key([mod, "control"], "q", lazy.shutdown(), desc="Shutdown Qtile"),
    Key([mod], "r", lazy.spawncmd(), desc="Spawn a command using a prompt widget"),
    Key([mod, "control"], "space", lazy.window.toggle_floating()),
    Key([mod, "shift"], "f", lazy.window.toggle_fullscreen()),

    
    #spawnprogs
    Key([mod], "u", lazy.spawn("subl -e /home/robabo/.config/qtile/config.py")),
    Key([mod], "z", lazy.spawn("/home/robabo/.config/qtile/rofi/bin/powermenu")),
    Key([mod], "f", lazy.spawn("thunar")), 
    Key([mod], "w", lazy.spawn("google-chrome-stable")),
    Key([mod], "x", lazy.spawn("/home/robabo/.config/openbox/rofi/bin/launcher")),
    Key([mod], "e", lazy.spawn("emacsclient -c -a emacs")),
    Key([mod], "n", lazy.spawn("alacritty -e ncmpcpp")),

]
layouts = [
    layout.MonadTall(border_focus='#121C25', border_width=1, margin=15),
    layout.Columns(border_focus_stack=['#d75f5f', '#8f3d3d'], border_width=4),
    layout.Max(),
    # Try more layouts by unleashing below layouts.
    # layout.Stack(num_stacks=2),
    # layout.Bsp(),
    # layout.Matrix(),
    # layout.MonadWide(),
    # layout.RatioTile(),
    # layout.Tile(),
    # layout.TreeTab(),
    # layout.VerticalTile(),
    # layout.Zoomy(),
]

groups = [
    Group('fst', position=1, label='ﮊ', layout='MonadTall'),
    Group('www', position=2, label='', layout='MonadTall'),
    Group('misc', position=3, label='ﭾ', layout='MonadTall'),
    Group('file', position=4, label='', layout='MonadTall'),
    Group('media', position=5, label='ﳜ', layout='max'),
    
    ]

# allow mod3+1 through mod3+0 to bind to groups; if you bind your groups
# by hand in your config, you don't need to do this.
dgroups_key_binder = simple_key_binder(mod)

#Functions

#uptime_command = ['/home/robabo/scripts/uptime']

#def get_uptime():
   # return subprocess.check_output(uptime_command).decode('utf-8').strip()

def open_calendar(qtile):
    from libqtile import qtile

def open_calendar():
    qtile.cmd_spawn('gsimplecal')


widget_defaults = dict(
    #font='mononoki nerd font',
    font='JetBrainsMono Nerd Font',
    fontsize=12,
    padding=3

)
extension_defaults = widget_defaults.copy()

screens = [
    Screen(
        top=bar.Bar(
            [   
                widget.Sep(
                    linewidth = 0,
                    padding = 5,
                    foreground ="#8A8D93"
                    ),

                widget.CurrentLayoutIcon(
                    scale=.5,
                    foreground='#80848b'
                    ),

                widget.GroupBox(
                    borderwidth=1, 
                    highlight_method='line', 
                    active='80848b', 
                    highlight_color='#121C25',
                    this_current_screen_border="#80848b"
                    ),

                widget.Prompt(),

                widget.WindowName(
                    foreground ="#80848b"
                    ),

                widget.Chord(
                    chords_colors={
                        'launch': ("#ff0000", "#ffffff"),
                    },
                    name_transform=lambda name: name.upper(),
                ),

                widget.TextBox(
                    text='',
                    #background='#282929',
                    foreground='#282929',
                    padding=-6,
                    fontsize=40
                    ),

                widget.Mpd2(
                    foreground='#80848b',
                    status_format='{play_status} {artist}/{title}',
                    idle_format='{play_status}',
                    background='#282929',
                    padding = 0,
                    ),

                #widget.GenPollText(
                   # func=get_uptime, 
                   # update_interval=1, 
                   # foreground='B1D0FF', 
                   # ),

                widget.TextBox(
                    text='|',
                    #background='#282929',
                    foreground='#282929',
                    padding=-10,
                    fontsize=40
                    ),

                widget.TextBox(
                    text='',
                    background='#282929',
                    foreground='#121c25',
                    padding=-6,
                    fontsize=40
                    ),

                widget.DF(
                    format = ' {p}: {f}G|{r:.0f}%',
                    visible_on_warn = False,
                    foreground='#80848b',
                    #background='#282929',
                    padding=6,
                    ),

                widget.TextBox(
                    text='',
                    #background='#282929',
                    foreground='#282929',
                    padding=-6,
                    fontsize=40
                    ),

                owm.OpenWeatherMap(
                    api_key="",
                    latitude= 43.3601,
                    longitude=-80.3127,
                    #icon_font="weather-icons",
                    foreground='#80848b',
                    background='#282929',
                    padding=5,
                    ),

                    widget.TextBox(
                    text='',
                    background='#282929',
                    foreground='#121c25',
                    padding=-6,
                    fontsize=40
                    ),

                widget.CheckUpdates(
                    distro="Arch_yay",
                    icon_size=12,
                    #background='#282929',
                    padding = 5,
                    colour_no_updates ="#80848b",
                    custom_command="checkupdates",
                    display_format= "  {updates}",
                    colour_have_updates="#8A8D93",
                    no_update_string = "",
                    update_interval=60
                    ),

                 widget.Sep(
                       linewidth = 0,
                       padding = 5,
                       foreground ="#8A8D93"
                       ),

                widget.TextBox(
                    text='',
                    #background='#282929',
                    foreground='#282929',
                    padding=-6,
                    fontsize=40
                    ),

                 widget.Clock(
                    foreground='#80848b',
                    background='#282929', 
                    format='%a %I:%M %p',
                    mouse_callbacks={'Button1': open_calendar},
                    padding = 4,
                    ),

                 widget.TextBox(
                    text='|',
                    #background='#282929',
                    foreground='#282929',
                    padding=-10,
                    fontsize=40
                    ),
                
                 widget.TextBox(
                    text='',
                    background='#282929',
                    foreground='#121c25',
                    padding=-6,
                    fontsize=40
                    ),

                 widget.WidgetBox(widgets=[
                    widget.Systray(
                        icon_size=17,
                        padding=0,
                        )
                        ],
                    close_button_location='right',
                    text_closed=' ﱲ ',
                    text_open=' ﱲ ',
                    foreground='#80848b',
                    padding=-2a
                    ),

                    widget.Sep(
                       linewidth = 0,
                       padding = 5,
                       foreground ="#8A8D93"
                       ),
            ],
            20, margin = [3, 0, 0, 0], 
            background="#00000000",
        ),
    
    ),
]

# Drag floating layouts.
mouse = [
    Drag([mod], "Button1", lazy.window.set_position_floating(),
         start=lazy.window.get_position()),
    Drag([mod], "Button3", lazy.window.set_size_floating(),
         start=lazy.window.get_size()),
    Click([mod], "Button2", lazy.window.bring_to_front())
]

#dgroups_key_binder = None
dgroups_app_rules = []  # type: List
follow_mouse_focus = True
bring_front_click = False
cursor_warp = False
floating_layout = layout.Floating(float_rules=[
    # Run the utility of `xprop` to see the wm class and name of an X client.
    *layout.Floating.default_float_rules,
    Match(wm_class='confirmreset'),  # gitk
    Match(wm_class='makebranch'),  # gitk
    Match(wm_class='maketag'),  # gitk
    Match(wm_class='ssh-askpass'),  # ssh-askpass
    Match(title='branchdialog'),  # gitk
    Match(title='pinentry'),  # GPG key password entry
    Match(wm_class='bomi'), #bomi player
    
],
border_focus="#8A8D93",
)

auto_fullscreen = True
focus_on_window_activation = "smart"
reconfigure_screens = True

# If things like steam games want to auto-minimize themselves when losing
# focus, should we respect this or not?
auto_minimize = True


@hook.subscribe.startup_once
def autostart():
    home = os.path.expanduser('~/.config/qtile/autostart.sh') # path to my script, under my user directory
    subprocess.call([home])


@hook.subscribe.client_new
def func(c):
    if c.name == "Mozilla Firefox":
        c.togroup("www", switch_group=True)  
    elif c.name == "New Tab - Google Chrome":
        c.togroup("www", switch_group=True)
    elif c.name == "Kodi":
        c.togroup("media", switch_group=True)
    
    
# XXX: Gasp! We're lying here. In fact, nobody really uses or cares about this
# string besides java UI toolkits; you can see several discussions on the
# mailing lists, GitHub issues, and other WM documentation that suggest setting
# this string if your java app doesn't work correctly. We may as well just lie
# and say that we're a working one by default.
#
# We choose LG3D to maximize irony: it is a 3D non-reparenting WM written in
# java that happens to be on java's whitelist.
wmname = "LG3D"
```

@elParaguayo I suspect 9069a0ed0afbf48d2e65182c82ade752a064dc87 is the cause here (again...). There is a systray in the widgetbox. 
Almost certainly due to that. Let me take a look...

Resolving patch:
diff --git a/libqtile/widget/widgetbox.py b/libqtile/widget/widgetbox.py
--- a/libqtile/widget/widgetbox.py
+++ b/libqtile/widget/widgetbox.py
@@ -120,7 +120,7 @@ def toggle_widgets(self):
                 # are separate _Window instances.
                 # Systray unhides icons when it draws so we only need to hide them.
                 if isinstance(widget, Systray):
-                    for icon in widget.icons.values():
+                    for icon in widget.tray_icons:
                         icon.hide()
 
             except ValueError:


Test patch: