Repository: pwr-Solaar/Solaar

Issue:
config_panel.py:535:_get_failed_spinner_control:AttributeError: 'VBox' object has no attribute '_failed'
**Information**
- Solaar version (`solaar --version` or `git describe --tags` if cloned from this repository): **1.0.6**
- Distribution: **Fedora 34**
- Kernel version (ex. `uname -srmo`): `5.13.13-200.fc34.x86_64`
- Output of `solaar show`:

<details>

```
N/A at this time, will update when original reporter provides it
```
</details>

**Describe the bug**
When clicking unlock/lock "disable keys" for keyboard "mx keys", solaar throws an `AttributeError` exception.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to Keyboard settings panel.
2. Click on lock/unlock icon for keyboard "mx keys".
3. `AttributeError` exception is thrown.

**Screenshots**
N/A

**Additional context**
This was reported downstream in Fedora bugzilla as bug [#2003483](https://bugzilla.redhat.com/show_bug.cgi?id=2003483).
Python backtrace:
```
config_panel.py:535:_get_failed_spinner_control:AttributeError: 'VBox' object has no attribute '_failed'

Traceback (most recent call last):
  File "/usr/lib/python3.9/site-packages/solaar/ui/config_panel.py", line 382, in _change_click
    _write_async(setting, persisted, control.get_parent())
  File "/usr/lib/python3.9/site-packages/solaar/ui/config_panel.py", line 44, in _write_async
    failed, spinner, control = _get_failed_spinner_control(sbox)
  File "/usr/lib/python3.9/site-packages/solaar/ui/config_panel.py", line 535, in _get_failed_spinner_control
    return sbox._failed, sbox._spinner, sbox._control
AttributeError: 'VBox' object has no attribute '_failed'

Local variables in innermost frame:
sbox: <Gtk.VBox object at 0x7f3f98d64a80 (GtkVBox at 0x559008a74f90)>
```


Discussion:
I can reproduce this bug.  Expect a patch soon.

Resolving patch:
diff --git a/lib/solaar/ui/config_panel.py b/lib/solaar/ui/config_panel.py
--- a/lib/solaar/ui/config_panel.py
+++ b/lib/solaar/ui/config_panel.py
@@ -190,7 +190,7 @@ def _toggle_notify(control, _, setting):
             if setting._value[key] != new_state:
                 setting._value[key] = new_state
                 p = control
-                for _ in range(5):
+                for _ in range(5):  # go up widget chain
                     p = p.get_parent()
                 _write_async_key_value(setting, key, new_state, p)
 
@@ -365,7 +365,7 @@ def _toggle_display(lb):
 
 # clicking on the lock icon changes from changeable to unchangeable to ignore
 def _change_click(eb, button, arg):
-    control, device, name = arg
+    control, sbox, device, name = arg
     icon = eb.get_children()[0]
     icon_name, _ = icon.get_icon_name()
     allowed = _icons_allowables.get(icon_name, True)
@@ -379,9 +379,9 @@ def _change_click(eb, button, arg):
         if setting:
             persisted = device.persister.get(setting.name) if device.persister else None
             if persisted is not None:
-                _write_async(setting, persisted, control.get_parent())
+                _write_async(setting, persisted, sbox)
             else:
-                _read_async(setting, True, control.get_parent(), bool(device.online), control.get_sensitive())
+                _read_async(setting, True, sbox, bool(device.online), control.get_sensitive())
     return True
 
 
@@ -432,7 +432,7 @@ def _create_sbox(s, device):
     control.kind = s.kind
 
     change.set_sensitive(True)
-    change.connect('button-press-event', _change_click, (control, device, s.name))
+    change.connect('button-press-event', _change_click, (control, sbox, device, s.name))
 
     if s.kind in [_SETTING_KIND.multiple_toggle, _SETTING_KIND.multiple_range]:
         vbox._header.pack_start(label, False, False, 0)


Test patch: