Python 3 ThreadPoolExecutor in Gtk 3
So I wanted to collect all the theme icons on my Linux machine so I wrote a little app. It is really fast using the ThreadPoolExecutor from futures. I’ve used this at work but never in a Gtk app. Here’s the result from the straight Python 3 code without a GUI. That’s a lot of images. I didn’t realize there are that many as Icon Browser displays nowhere near that amount.
Here’s the code.
from concurrent.futures import ThreadPoolExecutor import os import time def get_icons(): filter = ['.png','.svg'] base_path = '/usr/share/icons' for (dirpath, dirnames, filenames) in os.walk(base_path): if not filenames: continue # If not files found just skip path. # Filter by extension. for img in filenames: if os.path.splitext(img)[-1].strip().lower() not in filter: continue img_path = os.path.join(dirpath, img) yield img_path if __name__ in '__main__': start = time.time() with ThreadPoolExecutor(max_workers=25) as executor: task = executor.submit(get_icons) count=0 for img in task.result(): count += 1 print(img) print('total items: {0} took: {1} seconds'.format(count, time.time() - start))
Of course in Gtk you have added overhead but by limiting what I return it ran reasonably well. I might add a second list box to separate each theme, size, and type to reduce the overhead even more so we only load those small lists of icons on click. For this I just want ed to see if it would work as I have only used the thread library for Gtk in the past. Here’s the result.
I filter on 16px icons only. It’s still 5k worth of images. Here’s the code.
import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk,GObject,GdkPixbuf from concurrent.futures import ThreadPoolExecutor import os def get_icons(): filter = ['.png']#,'.svg'] base_path = '/usr/share/icons' for (dirpath, dirnames, filenames) in os.walk(base_path): if not filenames: continue # If not files found just skip path. if '16x16' not in dirpath.lower(): continue # limit amount as there are too many to load up. # Filter by extension. for img in filenames: if os.path.splitext(img)[-1].strip().lower() not in filter: continue img_path = os.path.join(dirpath, img) yield img_path class MyWindow(Gtk.Window): def __init__(self): Gtk.Window.__init__(self, title="PyCons") self.set_title("PyCons") self.set_default_size(800, 450) self.button = Gtk.Button(label="Fetch Icons") self.button.connect("clicked",self.fetch) self.status = Gtk.Label() self.status.set_text(' Idle') self.status.set_halign(Gtk.Align.START) self.vbox = Gtk.VBox() self.scroller = Gtk.ScrolledWindow() self.listbox = Gtk.ListBox() self.imgIcon = Gtk.Image() self.scroller.add(self.listbox) self.vbox.pack_start(self.button,False,False,5) self.vbox.pack_start(self.scroller,True,True,5) self.vbox.pack_end(self.status,False,False,5) self.add(self.vbox) def fetch(self,button): count=0 with ThreadPoolExecutor(max_workers=25) as executor: task = executor.submit(get_icons) for img_path in task.result(): count+=1 pixbuf = pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(img_path,16,16) icon = self.imgIcon.new_from_pixbuf(pixbuf) name = Gtk.Label() name.set_text(img_path.split('/')[-1].split('.')[0].strip()) path = Gtk.Label() path.set_text(img_path) row = Gtk.ListBoxRow() hbox = Gtk.HBox() hbox.pack_start(icon,False,False,10) hbox.pack_start(name,False,True,10) hbox.pack_end(path,False,True,1) row.add(hbox) self.listbox.insert(row,0) self.listbox.show_all() self.status.set_text(' Fetched %s items' % count) win = MyWindow() win.connect("destroy", Gtk.main_quit) win.show_all() Gtk.main()
So there you have it. Two ways to list the theme and system icons and images on your Ubuntu/Debian based system. If you need to do something heavy in a Gtk application this might be a easy solution for you.