Repository: qtile/qtile

Issue:
Drawbox width of the Tasklist widget not adjusted depending of icons number + icons not centered
### The issue:
 qtile --version :0.22.1

I wanted to get a tasklist widget with only centered icons and with a widget drawbox adjusted to the number of icon. Instead:
- The icons are placed on the left hand side
- using a non transparent color for the background we can see that the widget is taking more space than necessary.  This prevents the use of RectDecoration (at least to get good cosmetic results).

Ideally the width of the drawbox would be dynamically adjusted depending on the number of icons.

![image](https://user-images.githubusercontent.com/27446196/191791502-4d38c1d0-20fa-4d19-b3f9-225f447214fb.png)

Removal of text was obtained with 
```
def txt_remove(text): 
    text = ""
    return text
```
and in tasklist.widget
` parse_text=txt_remove,`


### Required:

- [X] I have searched past issues to see if this bug has already been reported.


Discussion:
If you restore the text, are the icons + text the size of that draw box? If so, we need to factor in the impact of the parse function when calculating the width of the widget.
From three tasks i can get the full width filled:
![image](https://user-images.githubusercontent.com/27446196/191805896-5a85bb0d-4fba-48ce-ae2f-a3b282557650.png)

With only two tasks there is still some space left on the right hand side:
![image](https://user-images.githubusercontent.com/27446196/191805738-38639d0f-23e0-4bc2-afb2-4e82dff51dfa.png)

Adding a launchbar on the left hand side, we can see that the total width of tasklist widget is adjusted
![image](https://user-images.githubusercontent.com/27446196/191806468-736782a1-e1e2-48eb-8524-b39920bcaef2.png)



Ah. This is a `STRETCH` widget so it fills available space. That's hardcoded at the moment.
I remember this rice that had a custom task list doing the job, if that helps:
https://www.reddit.com/r/unixporn/comments/wb2r57/final_rice_on_qtile/

Qtile dots:
https://github.com/ervinpopescu/dots-Lenovo/tree/main/.config/qtile
That TaskList doesn't change anything to do with its size.

If you want to use a decoration with this then we'd have to stop it being a stretch widget (which is hopefully pretty easy) but you would need to add a stretch widget after it if your bar doesn't have any other stretch widgets.
> I remember this rice that had a custom task list doing the job, if that helps:
> https://www.reddit.com/r/unixporn/comments/wb2r57/final_rice_on_qtile/
> 
> Qtile dots:
> https://github.com/ervinpopescu/dots-Lenovo/tree/main/.config/qtile

Hi, I'm the chef who made that rice :)

As you can see from the dots, the tasklist has a transparent background, the issue you are pointing out bugged me too. I tried to make something like a thumbnail for windows in the tasklist and came across this, tried fixing it by playing with the `calculate_length` method and the `__init__`, but that didn't work, so I eventually gave up, and then gave up on the thumbnail thing too, but not because of this issue.

So yeah, @elParaguayo is completely correct, but it would be nice if we had a way of not hardcoding the widget's length :)
I'll add to my list.
This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 30 days.
need update

Resolving patch:
diff --git a/libqtile/widget/tasklist.py b/libqtile/widget/tasklist.py
--- a/libqtile/widget/tasklist.py
+++ b/libqtile/widget/tasklist.py
@@ -32,7 +32,8 @@
 except ImportError:
     has_xdg = False
 
-from libqtile import bar, hook, pangocffi
+import libqtile.bar
+from libqtile import hook, pangocffi
 from libqtile.images import Img
 from libqtile.log_utils import logger
 from libqtile.widget import base
@@ -178,10 +179,15 @@ class TaskList(base._Widget, base.PaddingMixin, base.MarginMixin):
             0,
             "The offset given to the window location",
         ),
+        (
+            "stretch",
+            True,
+            "Widget fills available space in bar. Set to `False` to limit widget width to size of its contents.",
+        ),
     ]
 
     def __init__(self, **config):
-        base._Widget.__init__(self, bar.STRETCH, **config)
+        base._Widget.__init__(self, libqtile.bar.STRETCH, **config)
         self.add_defaults(TaskList.defaults)
         self.add_defaults(base.PaddingMixin.defaults)
         self.add_defaults(base.MarginMixin.defaults)
@@ -280,6 +286,12 @@ def windows(self):
             ]
         return self.bar.screen.group.windows
 
+    @property
+    def max_width(self):
+        width = self.bar.width
+        width -= sum(w.width for w in self.bar.widgets if w is not self)
+        return width
+
     def calc_box_widths(self):
         """
         Calculate box width for each window in current group.
@@ -294,7 +306,7 @@ def calc_box_widths(self):
             return []
 
         # Determine available and max average width for task name boxes.
-        width_total = self.width - 2 * self.margin_x - (window_count - 1) * self.spacing
+        width_total = self.max_width - 2 * self.margin_x - (window_count - 1) * self.spacing
         width_avg = width_total / window_count
 
         names = [self.get_taskname(w) for w in windows]
@@ -338,9 +350,21 @@ def calc_box_widths(self):
 
         return zip(windows, icons, names, width_boxes)
 
+    def calculate_length(self):
+        width = 10
+        box_widths = [box[3] for box in self.calc_box_widths()]
+        if box_widths:
+            width += self.spacing * len(box_widths) - 1
+            width += sum(w for w in box_widths)
+
+        return width
+
     def _configure(self, qtile, bar):
         base._Widget._configure(self, qtile, bar)
 
+        if not self.stretch:
+            self.length_type = libqtile.bar.CALCULATED
+
         if not has_xdg and self.theme_mode is not None:
             logger.warning("You must install pyxdg to use theme icons.")
             self.theme_mode = None


Test patch:
diff --git a/test/widgets/test_tasklist.py b/test/widgets/test_tasklist.py
--- a/test/widgets/test_tasklist.py
+++ b/test/widgets/test_tasklist.py
@@ -211,3 +211,15 @@ def test_tasklist_bad_theme_mode(tasklist_manager, logger):
 def test_tasklist_no_xdg(tasklist_manager, logger):
     msgs = [rec.msg for rec in logger.get_records("setup")]
     assert "You must install pyxdg to use theme icons." in msgs
+
+
+@configure_tasklist(stretch=False)
+def test_tasklist_no_stretch(tasklist_manager):
+    widget = tasklist_manager.c.widget["tasklist"]
+    tasklist_manager.test_window("One")
+    width_one = widget.info()["width"]
+
+    tasklist_manager.test_window("Two")
+    width_two = widget.info()["width"]
+
+    assert width_one != width_two