Repository: qtile/qtile

Issue:
widget.LaunchBar crashes on certain software_name and also will fill up the log because it cannot find images
### The issue:

```
            # widget.WidgetBox(widgets=[
            #         widget.LaunchBar(
            #             progs=[
            #               # (title, command, description)
            #               ('  ', terminal, 'Terminal'),
            #               ('  ', 'firefox', 'Browser'),
            #               ('  ', 'steam', 'Steam'),
            #               ('  ', 'dolphin', 'Filemanager'),
            #               ('  ', 'krunner', 'Run'),
            #               ('  ', 'jgmenu_run', 'App Menu'),
            #             ],
            #             padding=0,
            #         ),
            #     ],
            #     text_open='  ',
            #     text_closed='  ',
            #     font = fonts['awesome'],
            # ),

```

Now this is more an experimental thing I tried out. But I had it there and it seemingly works fine. Today I just realized the log file was multiple megabytes big. Qtile will always fallback to text mode, because I use text.
* If I write the name `thunderbird` the "software_name" in the "progs" list, then the Thunderbird icon will appear there without a problem.
* If I write the name `kitty` there, the widget crashes with following message in the log:
`2022-04-05 21:55:18,039 ERROR libqtile bar.py:_configure_widget():L350 WidgetBox widget crashed during _configure with error: MemoryError("cairo returned CAIRO_STATUS_NO_MEMORY: b'out of memory'", 1)`
* If I write a text in the "software_name" field, then text will be shown normally, but Qtile tries to lookup for images for no reason in this case and falls back to text mode. I can't tell the widget that its a text only.

Some system information:

- Your Qtile version (qtile --version): `0.21.1.dev8+gea4462b0`
- Relevant logs from ~/.local/share/qtile/qtile.log.
- If relevant, the problematic part of your config:
```
2022-04-05 21:48:41,184 WARNING libqtile launchbar.py:setup_images():L132 No icon found for application "  " (None) switch to text mode
2022-04-05 21:48:41,191 WARNING libqtile launchbar.py:setup_images():L132 No icon found for application "  " (None) switch to text mode
2022-04-05 21:48:41,191 WARNING libqtile launchbar.py:setup_images():L132 No icon found for application "  " (None) switch to text mode
2022-04-05 21:48:41,191 WARNING libqtile launchbar.py:setup_images():L132 No icon found for application "  " (None) switch to text mode
2022-04-05 21:48:41,192 WARNING libqtile launchbar.py:setup_images():L132 No icon found for application "  " (None) switch to text mode
2022-04-05 21:48:41,192 WARNING libqtile launchbar.py:setup_images():L132 No icon found for application "  " (None) switch to text mode
2022-04-05 21:55:18,039 ERROR libqtile bar.py:_configure_widget():L350 WidgetBox widget crashed during _configure with error: MemoryError("cairo returned CAIRO_STATUS_NO_MEMORY: b'out of memory'", 1)
```

```
OS: Manjaro Linux [x86_64]
Kernel: 5.16.14-1-MANJARO
Uptime: 1 day, 17 hours, 36 mins
Packages: 1896 (pacman)[stable], 1 (flatpak)
Shell: zsh 5.8.1
Resolution: 2560x1440 @ 144Hz
DE: KDE Plasma 5.24.3
WM: Qtile 0.21.1.dev8+gea4462b0
Theme: breeze (GruvboxColors) [Plasma], Klaus [GTK2/3/4]
Icons: breeze [Plasma], Gruvbox [GTK2/3/4]
Font: Noto Sans (12pt) [Plasma], Noto Sans (12pt) [GTK2/3/4]
Cursor: default (24px)
Terminal: kitty
CPU: Intel Xeon E3-1230 v3 (8) @ 3.7GHz
GPU: Nvidia GeForce GTX 1070
Memory: 3225MiB / 15947MiB (20%)
Disk (/): 98GB / 219GB (44%)
Locale: de_DE.UTF-8
```

### Required:

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


Discussion:
OK. I can recreate this. I get the same memory error if I try to add `kitty`. Weird!
Thanks for checking out. I think it would make sense to have an option to tell Qtile this to be text only and not checking anything. It would not litter the log file and it would make it easier if I want to use the name "kitty" literally.
Yeah - text only could be added as an option.

As for kitty, it looks like it's crashing because the icon is in svg format but the widget is expecting a png.

Resolving patch:
diff --git a/libqtile/widget/launchbar.py b/libqtile/widget/launchbar.py
--- a/libqtile/widget/launchbar.py
+++ b/libqtile/widget/launchbar.py
@@ -83,6 +83,7 @@ class LaunchBar(base._Widget):
             " [('thunderbird', 'thunderbird -safe-mode', 'launch thunderbird in safe mode'), "
             " ('logout', 'qshell:self.qtile.cmd_shutdown()', 'logout from qtile')]",
         ),
+        ("text_only", False, "Don't use any icons."),
     ]
 
     def __init__(
@@ -128,12 +129,14 @@ def _configure(self, qtile, pbar):
     def setup_images(self):
         """Create image structures for each icon files."""
         for img_name, iconfile in self.icons_files.items():
-            if iconfile is None:
-                logger.warning(
-                    'No icon found for application "%s" (%s) switch to text mode',
-                    img_name,
-                    iconfile,
-                )
+            if iconfile is None or self.text_only:
+                # Only warn the user that there's no icon if they haven't set text only mode
+                if not self.text_only:
+                    logger.warning(
+                        'No icon found for application "%s" (%s) switch to text mode',
+                        img_name,
+                        iconfile,
+                    )
                 # if no icon is found and no default icon was set, we just
                 # print the name, based on a textbox.
                 textbox = base._TextBox()
@@ -154,20 +157,20 @@ def setup_images(self):
                 continue
             else:
                 try:
-                    img = cairocffi.ImageSurface.create_from_png(iconfile)
+                    img = Img.from_path(iconfile)
                 except cairocffi.Error:
                     logger.exception(
                         'Error loading icon for application "%s" (%s)', img_name, iconfile
                     )
                     return
 
-            input_width = img.get_width()
-            input_height = img.get_height()
+            input_width = img.width
+            input_height = img.height
 
             sp = input_height / (self.bar.height - 4)
             width = int(input_width / sp)
 
-            imgpat = cairocffi.SurfacePattern(img)
+            imgpat = cairocffi.SurfacePattern(img.surface)
             scaler = cairocffi.Matrix()
             scaler.scale(sp, sp)
             scaler.translate(self.padding * -1, -2)


Test patch: