Repository: qtile/qtile

Issue:
Chord widget doesn't have default background colour
### The issue:

The background colour is set by looking up the chord name in a dictionary. If the name is not in the dictionary then the chord will be displayed with whatever the current background colour is.

The widget needs to be updated to restore colours to defaults.

### Required:

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


Discussion:

Resolving patch:
diff --git a/libqtile/widget/chord.py b/libqtile/widget/chord.py
--- a/libqtile/widget/chord.py
+++ b/libqtile/widget/chord.py
@@ -29,7 +29,13 @@ class Chord(base._TextBox):
     """Display current key chord"""
 
     defaults = [
-        ("chords_colors", {}, "colors per chord in form of tuple ('bg', 'fg')."),
+        (
+            "chords_colors",
+            {},
+            "colors per chord in form of tuple {'chord_name': ('bg', 'fg')}. "
+            "Where a chord name is not in the dictionary, the default ``background`` and ``foreground``"
+            " values will be used.",
+        ),
         (
             "name_transform",
             lambda txt: txt,
@@ -43,6 +49,8 @@ def __init__(self, width=bar.CALCULATED, **config):
 
     def _configure(self, qtile, bar):
         base._TextBox._configure(self, qtile, bar)
+        self.default_background = self.background
+        self.default_foreground = self.foreground
         self.text = ""
         self._setup_hooks()
 
@@ -50,17 +58,25 @@ def _setup_hooks(self):
         def hook_enter_chord(chord_name):
             if chord_name is True:
                 self.text = ""
+                self.reset_colours()
                 return
 
             self.text = self.name_transform(chord_name)
             if chord_name in self.chords_colors:
                 (self.background, self.foreground) = self.chords_colors.get(chord_name)
+            else:
+                self.reset_colours()
 
             self.bar.draw()
 
         hook.subscribe.enter_chord(hook_enter_chord)
         hook.subscribe.leave_chord(self.clear)
 
+    def reset_colours(self):
+        self.background = self.default_background
+        self.foreground = self.default_foreground
+
     def clear(self, *args):
+        self.reset_colours()
         self.text = ""
         self.bar.draw()


Test patch:
diff --git a/test/widgets/test_chord.py b/test/widgets/test_chord.py
--- a/test/widgets/test_chord.py
+++ b/test/widgets/test_chord.py
@@ -1,5 +1,6 @@
 from libqtile import hook
 from libqtile.widget import Chord, base
+from test.widgets.conftest import FakeBar
 
 RED = "#FF0000"
 BLUE = "#00FF00"
@@ -9,19 +10,45 @@
 BASE_FOREGROUND = textbox.foreground
 
 
-def test_chord_widget(fake_bar):
+def test_chord_widget(fake_window, fake_qtile):
     chord = Chord(chords_colors={"testcolor": (RED, BLUE)})
-    chord.bar = fake_bar
-    chord._setup_hooks()
+    fakebar = FakeBar([chord], window=fake_window)
+    chord._configure(fake_qtile, fakebar)
+
+    # Text is blank at start
     assert chord.text == ""
+
+    # Fire hook for testcolor chord
+    hook.fire("enter_chord", "testcolor")
+
+    # Chord is in chords_colors so check colours
+    assert chord.background == RED
+    assert chord.foreground == BLUE
+    assert chord.text == "testcolor"
+
+    # New chord, not in dictionary so should be default colours
     hook.fire("enter_chord", "test")
     assert chord.text == "test"
     assert chord.background == BASE_BACKGROUND
     assert chord.foreground == BASE_FOREGROUND
+
+    # Unnamed chord so no text
     hook.fire("enter_chord", True)
     assert chord.text == ""
-    hook.fire("leave_chord")
-    assert chord.text == ""
+    assert chord.background == BASE_BACKGROUND
+    assert chord.foreground == BASE_FOREGROUND
+
+    # Back into testcolor and custom colours
     hook.fire("enter_chord", "testcolor")
     assert chord.background == RED
     assert chord.foreground == BLUE
+    assert chord.text == "testcolor"
+
+    # Colours shoud reset when leaving chord
+    hook.fire("leave_chord")
+    assert chord.text == ""
+    assert chord.background == BASE_BACKGROUND
+    assert chord.foreground == BASE_FOREGROUND
+
+    # Finalize the widget to prevent segfault
+    chord.finalize()