We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
libqtile utils.py:safe_import():L192  Unmet dependencies for optional Widget: '.widget.launchbar.LaunchBar', No module named 'xdg.IconTheme'
It seems there's confusion about the `xdg` dependency that is used. The code expects [PyXDG](https://freedesktop.org/wiki/Software/pyxdg/) while the actual installed version is [xdg](https://pypi.org/project/xdg/). The latter does not have an `IconTheme` submodule, explaining the message.

The distribution name for `pyxdg` is  `pyxdg` (not `xdg`).

https://github.com/qtile/qtile/blob/0d8b6e5de1cacb9827c4b30ce7ed8da4bb686f26/libqtile/widget/launchbar.py#L49

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `libqtile/widget/launchbar.py`
Content:
```
1 # Copyright (c) 2014 Tycho Andersen
2 # Copyright (c) 2014 dequis
3 # Copyright (c) 2014-2015 Joseph Razik
4 # Copyright (c) 2014 Sean Vig
5 # Copyright (c) 2015 reus
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 # SOFTWARE.
24 
25 """
26 This module define a widget that displays icons to launch softwares or commands
27 when clicked -- a launchbar.
28 Only png icon files are displayed, not xpm because cairo doesn't support
29 loading of xpm file.
30 The order of displaying (from left to right) is in the order of the list.
31 
32 If no icon was found for the name provided and if default_icon is set to None
33 then the name is printed instead. If default_icon is defined then this icon is
34 displayed instead.
35 
36 To execute a software:
37  - ('thunderbird', 'thunderbird -safe-mode', 'launch thunderbird in safe mode')
38 To execute a python command in qtile, begin with by 'qshell:'
39  - ('logout', 'qshell:self.qtile.cmd_shutdown()', 'logout from qtile')
40 
41 
42 """
43 from libqtile import bar
44 from libqtile.log_utils import logger
45 from libqtile.widget import base
46 
47 import os.path
48 import cairocffi
49 from xdg.IconTheme import getIconPath
50 
51 
52 class LaunchBar(base._Widget):
53     """A widget that display icons to launch the associated command
54 
55     Parameters
56     ==========
57     progs :
58         a list of tuples ``(software_name, command_to_execute, comment)``, for
59         example::
60 
61             ('thunderbird', 'thunderbird -safe-mode', 'launch thunderbird in safe mode')
62             ('logout', 'qshell:self.qtile.cmd_shutdown()', 'logout from qtile')
63     """
64     orientations = base.ORIENTATION_HORIZONTAL
65     defaults = [
66         ('padding', 2, 'Padding between icons'),
67         ('default_icon', '/usr/share/icons/oxygen/256x256/mimetypes/'
68          'application-x-executable.png', 'Default icon not found'),
69     ]
70 
71     def __init__(self, progs=None, width=bar.CALCULATED, **config):
72         base._Widget.__init__(self, width, **config)
73         if progs is None:
74             progs = []
75         self.add_defaults(LaunchBar.defaults)
76         self.surfaces = {}
77         self.icons_files = {}
78         self.icons_widths = {}
79         self.icons_offsets = {}
80         # For now, ignore the comments but may be one day it will be useful
81         self.progs = dict(enumerate([{'name': prog[0], 'cmd': prog[1],
82                                       'comment': prog[2] if len(prog) > 2 else
83                                       None} for prog in progs]))
84         self.progs_name = set([prog['name'] for prog in self.progs.values()])
85         self.length_type = bar.STATIC
86         self.length = 0
87 
88     def _configure(self, qtile, pbar):
89         base._Widget._configure(self, qtile, pbar)
90         self.lookup_icons()
91         self.setup_images()
92         self.length = self.calculate_length()
93 
94     def setup_images(self):
95         """ Create image structures for each icon files. """
96         for img_name, iconfile in self.icons_files.items():
97             if iconfile is None:
98                 logger.warning(
99                     'No icon found for application "%s" (%s) switch to text mode',
100                     img_name, iconfile)
101                 # if no icon is found and no default icon was set, we just
102                 # print the name, based on a textbox.
103                 textbox = base._TextBox()
104                 textbox._configure(self.qtile, self.bar)
105                 textbox.layout = self.drawer.textlayout(
106                     textbox.text,
107                     textbox.foreground,
108                     textbox.font,
109                     textbox.fontsize,
110                     textbox.fontshadow,
111                     markup=textbox.markup,
112                 )
113                 # the name will be displayed
114                 textbox.text = img_name
115                 textbox.calculate_length()
116                 self.icons_widths[img_name] = textbox.width
117                 self.surfaces[img_name] = textbox
118                 continue
119             else:
120                 try:
121                     img = cairocffi.ImageSurface.create_from_png(iconfile)
122                 except cairocffi.Error:
123                     logger.exception('Error loading icon for application "%s" (%s)', img_name, iconfile)
124                     return
125 
126             input_width = img.get_width()
127             input_height = img.get_height()
128 
129             sp = input_height / (self.bar.height - 4)
130             width = int(input_width / sp)
131 
132             imgpat = cairocffi.SurfacePattern(img)
133             scaler = cairocffi.Matrix()
134             scaler.scale(sp, sp)
135             scaler.translate(self.padding * -1, -2)
136             imgpat.set_matrix(scaler)
137 
138             imgpat.set_filter(cairocffi.FILTER_BEST)
139             self.surfaces[img_name] = imgpat
140             self.icons_widths[img_name] = width
141 
142     def _lookup_icon(self, name):
143         """ Search for the icon corresponding to one command. """
144         self.icons_files[name] = None
145         # if the software_name is directly an absolute path icon file
146         if os.path.isabs(name):
147             # name start with '/' thus it's an absolute path
148             root, ext = os.path.splitext(name)
149             if ext == '.png':
150                 self.icons_files[name] = name if os.path.isfile(name) else None
151             else:
152                 # try to add the extension
153                 self.icons_files[name] = name + '.png' if os.path.isfile(name + '.png') else None
154         else:
155             self.icons_files[name] = getIconPath(name)
156         # no search method found an icon, so default icon
157         if self.icons_files[name] is None:
158             self.icons_files[name] = self.default_icon
159 
160     def lookup_icons(self):
161         """ Search for the icons corresponding to the commands to execute. """
162         if self.default_icon is not None:
163             if not os.path.isfile(self.default_icon):
164                 # if the default icon provided is not found, switch to
165                 # text mode
166                 self.default_icon = None
167         for name in self.progs_name:
168             self._lookup_icon(name)
169 
170     def get_icon_in_position(self, x, y):
171         """ Determine which icon is clicked according to its position. """
172         for i in self.progs:
173             if x < (self.icons_offsets[i] +
174                     self.icons_widths[self.progs[i]['name']] +
175                     self.padding / 2):
176                 return i
177 
178     def button_press(self, x, y, button):
179         """ Launch the associated command to the clicked icon. """
180         if button == 1:
181             icon = self.get_icon_in_position(x, y)
182             if icon is not None:
183                 cmd = self.progs[icon]['cmd']
184                 if cmd.startswith('qshell:'):
185                     exec(cmd[7:].lstrip())
186                 else:
187                     self.qtile.cmd_spawn(cmd)
188             self.draw()
189 
190     def draw(self):
191         """ Draw the icons in the widget. """
192         self.drawer.clear(self.background or self.bar.background)
193         xoffset = 0
194         for i in sorted(self.progs.keys()):
195             self.icons_offsets[i] = xoffset + self.padding
196             name = self.progs[i]['name']
197             icon_width = self.icons_widths[name]
198             self.drawer.ctx.move_to(self.offset + xoffset, icon_width)
199             self.drawer.clear(self.background or self.bar.background)
200             if isinstance(self.surfaces[name], base._TextBox):
201                 # display the name if no icon was found and no default icon
202                 textbox = self.surfaces[name]
203                 textbox.layout.draw(
204                     self.padding + textbox.actual_padding,
205                     int((self.bar.height - textbox.layout.height) / 2.0) + 1
206                 )
207             else:
208                 # display an icon
209                 self.drawer.ctx.set_source(self.surfaces[name])
210                 self.drawer.ctx.paint()
211             self.drawer.draw(offsetx=self.offset + xoffset,
212                              width=icon_width + self.padding)
213             xoffset += icon_width + self.padding
214 
215     def calculate_length(self):
216         """ Compute the width of the widget according to each icon width. """
217         return sum(self.icons_widths[prg['name']] for prg in self.progs.values()) \
218             + self.padding * (len(self.progs) + 1)
219
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/libqtile/widget/launchbar.py b/libqtile/widget/launchbar.py
--- a/libqtile/widget/launchbar.py
+++ b/libqtile/widget/launchbar.py
@@ -52,6 +52,10 @@
 class LaunchBar(base._Widget):
     """A widget that display icons to launch the associated command
 
+    Widget requirements: pyxdg_.
+
+    .. _pyxdg: https://freedesktop.org/wiki/Software/pyxdg/
+
     Parameters
     ==========
     progs :

{"golden_diff": "diff --git a/libqtile/widget/launchbar.py b/libqtile/widget/launchbar.py\n--- a/libqtile/widget/launchbar.py\n+++ b/libqtile/widget/launchbar.py\n@@ -52,6 +52,10 @@\n class LaunchBar(base._Widget):\n     \"\"\"A widget that display icons to launch the associated command\n \n+    Widget requirements: pyxdg_.\n+\n+    .. _pyxdg: https://freedesktop.org/wiki/Software/pyxdg/\n+\n     Parameters\n     ==========\n     progs :\n", "issue": "libqtile utils.py:safe_import():L192  Unmet dependencies for optional Widget: '.widget.launchbar.LaunchBar', No module named 'xdg.IconTheme'\nIt seems there's confusion about the `xdg` dependency that is used. The code expects [PyXDG](https://freedesktop.org/wiki/Software/pyxdg/) while the actual installed version is [xdg](https://pypi.org/project/xdg/). The latter does not have an `IconTheme` submodule, explaining the message.\r\n\r\nThe distribution name for `pyxdg` is  `pyxdg` (not `xdg`).\r\n\r\nhttps://github.com/qtile/qtile/blob/0d8b6e5de1cacb9827c4b30ce7ed8da4bb686f26/libqtile/widget/launchbar.py#L49\n", "before_files": [{"content": "# Copyright (c) 2014 Tycho Andersen\n# Copyright (c) 2014 dequis\n# Copyright (c) 2014-2015 Joseph Razik\n# Copyright (c) 2014 Sean Vig\n# Copyright (c) 2015 reus\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n\"\"\"\nThis module define a widget that displays icons to launch softwares or commands\nwhen clicked -- a launchbar.\nOnly png icon files are displayed, not xpm because cairo doesn't support\nloading of xpm file.\nThe order of displaying (from left to right) is in the order of the list.\n\nIf no icon was found for the name provided and if default_icon is set to None\nthen the name is printed instead. If default_icon is defined then this icon is\ndisplayed instead.\n\nTo execute a software:\n - ('thunderbird', 'thunderbird -safe-mode', 'launch thunderbird in safe mode')\nTo execute a python command in qtile, begin with by 'qshell:'\n - ('logout', 'qshell:self.qtile.cmd_shutdown()', 'logout from qtile')\n\n\n\"\"\"\nfrom libqtile import bar\nfrom libqtile.log_utils import logger\nfrom libqtile.widget import base\n\nimport os.path\nimport cairocffi\nfrom xdg.IconTheme import getIconPath\n\n\nclass LaunchBar(base._Widget):\n    \"\"\"A widget that display icons to launch the associated command\n\n    Parameters\n    ==========\n    progs :\n        a list of tuples ``(software_name, command_to_execute, comment)``, for\n        example::\n\n            ('thunderbird', 'thunderbird -safe-mode', 'launch thunderbird in safe mode')\n            ('logout', 'qshell:self.qtile.cmd_shutdown()', 'logout from qtile')\n    \"\"\"\n    orientations = base.ORIENTATION_HORIZONTAL\n    defaults = [\n        ('padding', 2, 'Padding between icons'),\n        ('default_icon', '/usr/share/icons/oxygen/256x256/mimetypes/'\n         'application-x-executable.png', 'Default icon not found'),\n    ]\n\n    def __init__(self, progs=None, width=bar.CALCULATED, **config):\n        base._Widget.__init__(self, width, **config)\n        if progs is None:\n            progs = []\n        self.add_defaults(LaunchBar.defaults)\n        self.surfaces = {}\n        self.icons_files = {}\n        self.icons_widths = {}\n        self.icons_offsets = {}\n        # For now, ignore the comments but may be one day it will be useful\n        self.progs = dict(enumerate([{'name': prog[0], 'cmd': prog[1],\n                                      'comment': prog[2] if len(prog) > 2 else\n                                      None} for prog in progs]))\n        self.progs_name = set([prog['name'] for prog in self.progs.values()])\n        self.length_type = bar.STATIC\n        self.length = 0\n\n    def _configure(self, qtile, pbar):\n        base._Widget._configure(self, qtile, pbar)\n        self.lookup_icons()\n        self.setup_images()\n        self.length = self.calculate_length()\n\n    def setup_images(self):\n        \"\"\" Create image structures for each icon files. \"\"\"\n        for img_name, iconfile in self.icons_files.items():\n            if iconfile is None:\n                logger.warning(\n                    'No icon found for application \"%s\" (%s) switch to text mode',\n                    img_name, iconfile)\n                # if no icon is found and no default icon was set, we just\n                # print the name, based on a textbox.\n                textbox = base._TextBox()\n                textbox._configure(self.qtile, self.bar)\n                textbox.layout = self.drawer.textlayout(\n                    textbox.text,\n                    textbox.foreground,\n                    textbox.font,\n                    textbox.fontsize,\n                    textbox.fontshadow,\n                    markup=textbox.markup,\n                )\n                # the name will be displayed\n                textbox.text = img_name\n                textbox.calculate_length()\n                self.icons_widths[img_name] = textbox.width\n                self.surfaces[img_name] = textbox\n                continue\n            else:\n                try:\n                    img = cairocffi.ImageSurface.create_from_png(iconfile)\n                except cairocffi.Error:\n                    logger.exception('Error loading icon for application \"%s\" (%s)', img_name, iconfile)\n                    return\n\n            input_width = img.get_width()\n            input_height = img.get_height()\n\n            sp = input_height / (self.bar.height - 4)\n            width = int(input_width / sp)\n\n            imgpat = cairocffi.SurfacePattern(img)\n            scaler = cairocffi.Matrix()\n            scaler.scale(sp, sp)\n            scaler.translate(self.padding * -1, -2)\n            imgpat.set_matrix(scaler)\n\n            imgpat.set_filter(cairocffi.FILTER_BEST)\n            self.surfaces[img_name] = imgpat\n            self.icons_widths[img_name] = width\n\n    def _lookup_icon(self, name):\n        \"\"\" Search for the icon corresponding to one command. \"\"\"\n        self.icons_files[name] = None\n        # if the software_name is directly an absolute path icon file\n        if os.path.isabs(name):\n            # name start with '/' thus it's an absolute path\n            root, ext = os.path.splitext(name)\n            if ext == '.png':\n                self.icons_files[name] = name if os.path.isfile(name) else None\n            else:\n                # try to add the extension\n                self.icons_files[name] = name + '.png' if os.path.isfile(name + '.png') else None\n        else:\n            self.icons_files[name] = getIconPath(name)\n        # no search method found an icon, so default icon\n        if self.icons_files[name] is None:\n            self.icons_files[name] = self.default_icon\n\n    def lookup_icons(self):\n        \"\"\" Search for the icons corresponding to the commands to execute. \"\"\"\n        if self.default_icon is not None:\n            if not os.path.isfile(self.default_icon):\n                # if the default icon provided is not found, switch to\n                # text mode\n                self.default_icon = None\n        for name in self.progs_name:\n            self._lookup_icon(name)\n\n    def get_icon_in_position(self, x, y):\n        \"\"\" Determine which icon is clicked according to its position. \"\"\"\n        for i in self.progs:\n            if x < (self.icons_offsets[i] +\n                    self.icons_widths[self.progs[i]['name']] +\n                    self.padding / 2):\n                return i\n\n    def button_press(self, x, y, button):\n        \"\"\" Launch the associated command to the clicked icon. \"\"\"\n        if button == 1:\n            icon = self.get_icon_in_position(x, y)\n            if icon is not None:\n                cmd = self.progs[icon]['cmd']\n                if cmd.startswith('qshell:'):\n                    exec(cmd[7:].lstrip())\n                else:\n                    self.qtile.cmd_spawn(cmd)\n            self.draw()\n\n    def draw(self):\n        \"\"\" Draw the icons in the widget. \"\"\"\n        self.drawer.clear(self.background or self.bar.background)\n        xoffset = 0\n        for i in sorted(self.progs.keys()):\n            self.icons_offsets[i] = xoffset + self.padding\n            name = self.progs[i]['name']\n            icon_width = self.icons_widths[name]\n            self.drawer.ctx.move_to(self.offset + xoffset, icon_width)\n            self.drawer.clear(self.background or self.bar.background)\n            if isinstance(self.surfaces[name], base._TextBox):\n                # display the name if no icon was found and no default icon\n                textbox = self.surfaces[name]\n                textbox.layout.draw(\n                    self.padding + textbox.actual_padding,\n                    int((self.bar.height - textbox.layout.height) / 2.0) + 1\n                )\n            else:\n                # display an icon\n                self.drawer.ctx.set_source(self.surfaces[name])\n                self.drawer.ctx.paint()\n            self.drawer.draw(offsetx=self.offset + xoffset,\n                             width=icon_width + self.padding)\n            xoffset += icon_width + self.padding\n\n    def calculate_length(self):\n        \"\"\" Compute the width of the widget according to each icon width. \"\"\"\n        return sum(self.icons_widths[prg['name']] for prg in self.progs.values()) \\\n            + self.padding * (len(self.progs) + 1)\n", "path": "libqtile/widget/launchbar.py"}], "after_files": [{"content": "# Copyright (c) 2014 Tycho Andersen\n# Copyright (c) 2014 dequis\n# Copyright (c) 2014-2015 Joseph Razik\n# Copyright (c) 2014 Sean Vig\n# Copyright (c) 2015 reus\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n\"\"\"\nThis module define a widget that displays icons to launch softwares or commands\nwhen clicked -- a launchbar.\nOnly png icon files are displayed, not xpm because cairo doesn't support\nloading of xpm file.\nThe order of displaying (from left to right) is in the order of the list.\n\nIf no icon was found for the name provided and if default_icon is set to None\nthen the name is printed instead. If default_icon is defined then this icon is\ndisplayed instead.\n\nTo execute a software:\n - ('thunderbird', 'thunderbird -safe-mode', 'launch thunderbird in safe mode')\nTo execute a python command in qtile, begin with by 'qshell:'\n - ('logout', 'qshell:self.qtile.cmd_shutdown()', 'logout from qtile')\n\n\n\"\"\"\nfrom libqtile import bar\nfrom libqtile.log_utils import logger\nfrom libqtile.widget import base\n\nimport os.path\nimport cairocffi\nfrom xdg.IconTheme import getIconPath\n\n\nclass LaunchBar(base._Widget):\n    \"\"\"A widget that display icons to launch the associated command\n\n    Widget requirements: pyxdg_.\n\n    .. _pyxdg: https://freedesktop.org/wiki/Software/pyxdg/\n\n    Parameters\n    ==========\n    progs :\n        a list of tuples ``(software_name, command_to_execute, comment)``, for\n        example::\n\n            ('thunderbird', 'thunderbird -safe-mode', 'launch thunderbird in safe mode')\n            ('logout', 'qshell:self.qtile.cmd_shutdown()', 'logout from qtile')\n    \"\"\"\n    orientations = base.ORIENTATION_HORIZONTAL\n    defaults = [\n        ('padding', 2, 'Padding between icons'),\n        ('default_icon', '/usr/share/icons/oxygen/256x256/mimetypes/'\n         'application-x-executable.png', 'Default icon not found'),\n    ]\n\n    def __init__(self, progs=None, width=bar.CALCULATED, **config):\n        base._Widget.__init__(self, width, **config)\n        if progs is None:\n            progs = []\n        self.add_defaults(LaunchBar.defaults)\n        self.surfaces = {}\n        self.icons_files = {}\n        self.icons_widths = {}\n        self.icons_offsets = {}\n        # For now, ignore the comments but may be one day it will be useful\n        self.progs = dict(enumerate([{'name': prog[0], 'cmd': prog[1],\n                                      'comment': prog[2] if len(prog) > 2 else\n                                      None} for prog in progs]))\n        self.progs_name = set([prog['name'] for prog in self.progs.values()])\n        self.length_type = bar.STATIC\n        self.length = 0\n\n    def _configure(self, qtile, pbar):\n        base._Widget._configure(self, qtile, pbar)\n        self.lookup_icons()\n        self.setup_images()\n        self.length = self.calculate_length()\n\n    def setup_images(self):\n        \"\"\" Create image structures for each icon files. \"\"\"\n        for img_name, iconfile in self.icons_files.items():\n            if iconfile is None:\n                logger.warning(\n                    'No icon found for application \"%s\" (%s) switch to text mode',\n                    img_name, iconfile)\n                # if no icon is found and no default icon was set, we just\n                # print the name, based on a textbox.\n                textbox = base._TextBox()\n                textbox._configure(self.qtile, self.bar)\n                textbox.layout = self.drawer.textlayout(\n                    textbox.text,\n                    textbox.foreground,\n                    textbox.font,\n                    textbox.fontsize,\n                    textbox.fontshadow,\n                    markup=textbox.markup,\n                )\n                # the name will be displayed\n                textbox.text = img_name\n                textbox.calculate_length()\n                self.icons_widths[img_name] = textbox.width\n                self.surfaces[img_name] = textbox\n                continue\n            else:\n                try:\n                    img = cairocffi.ImageSurface.create_from_png(iconfile)\n                except cairocffi.Error:\n                    logger.exception('Error loading icon for application \"%s\" (%s)', img_name, iconfile)\n                    return\n\n            input_width = img.get_width()\n            input_height = img.get_height()\n\n            sp = input_height / (self.bar.height - 4)\n            width = int(input_width / sp)\n\n            imgpat = cairocffi.SurfacePattern(img)\n            scaler = cairocffi.Matrix()\n            scaler.scale(sp, sp)\n            scaler.translate(self.padding * -1, -2)\n            imgpat.set_matrix(scaler)\n\n            imgpat.set_filter(cairocffi.FILTER_BEST)\n            self.surfaces[img_name] = imgpat\n            self.icons_widths[img_name] = width\n\n    def _lookup_icon(self, name):\n        \"\"\" Search for the icon corresponding to one command. \"\"\"\n        self.icons_files[name] = None\n        # if the software_name is directly an absolute path icon file\n        if os.path.isabs(name):\n            # name start with '/' thus it's an absolute path\n            root, ext = os.path.splitext(name)\n            if ext == '.png':\n                self.icons_files[name] = name if os.path.isfile(name) else None\n            else:\n                # try to add the extension\n                self.icons_files[name] = name + '.png' if os.path.isfile(name + '.png') else None\n        else:\n            self.icons_files[name] = getIconPath(name)\n        # no search method found an icon, so default icon\n        if self.icons_files[name] is None:\n            self.icons_files[name] = self.default_icon\n\n    def lookup_icons(self):\n        \"\"\" Search for the icons corresponding to the commands to execute. \"\"\"\n        if self.default_icon is not None:\n            if not os.path.isfile(self.default_icon):\n                # if the default icon provided is not found, switch to\n                # text mode\n                self.default_icon = None\n        for name in self.progs_name:\n            self._lookup_icon(name)\n\n    def get_icon_in_position(self, x, y):\n        \"\"\" Determine which icon is clicked according to its position. \"\"\"\n        for i in self.progs:\n            if x < (self.icons_offsets[i] +\n                    self.icons_widths[self.progs[i]['name']] +\n                    self.padding / 2):\n                return i\n\n    def button_press(self, x, y, button):\n        \"\"\" Launch the associated command to the clicked icon. \"\"\"\n        if button == 1:\n            icon = self.get_icon_in_position(x, y)\n            if icon is not None:\n                cmd = self.progs[icon]['cmd']\n                if cmd.startswith('qshell:'):\n                    exec(cmd[7:].lstrip())\n                else:\n                    self.qtile.cmd_spawn(cmd)\n            self.draw()\n\n    def draw(self):\n        \"\"\" Draw the icons in the widget. \"\"\"\n        self.drawer.clear(self.background or self.bar.background)\n        xoffset = 0\n        for i in sorted(self.progs.keys()):\n            self.icons_offsets[i] = xoffset + self.padding\n            name = self.progs[i]['name']\n            icon_width = self.icons_widths[name]\n            self.drawer.ctx.move_to(self.offset + xoffset, icon_width)\n            self.drawer.clear(self.background or self.bar.background)\n            if isinstance(self.surfaces[name], base._TextBox):\n                # display the name if no icon was found and no default icon\n                textbox = self.surfaces[name]\n                textbox.layout.draw(\n                    self.padding + textbox.actual_padding,\n                    int((self.bar.height - textbox.layout.height) / 2.0) + 1\n                )\n            else:\n                # display an icon\n                self.drawer.ctx.set_source(self.surfaces[name])\n                self.drawer.ctx.paint()\n            self.drawer.draw(offsetx=self.offset + xoffset,\n                             width=icon_width + self.padding)\n            xoffset += icon_width + self.padding\n\n    def calculate_length(self):\n        \"\"\" Compute the width of the widget according to each icon width. \"\"\"\n        return sum(self.icons_widths[prg['name']] for prg in self.progs.values()) \\\n            + self.padding * (len(self.progs) + 1)\n", "path": "libqtile/widget/launchbar.py"}]}