Don't use the name 'item'. Nodes are nodes, fullpaths are fullpaths.
[pysize.git] / pysize / ui / gtk / threaded_pysize_tree.py
blobada6218701c3b04d4a6b88d0ce679f8cd577efd4
1 from threading import Thread
2 from Queue import Queue
3 import gobject
5 from pysize.core.observable import observable
6 from pysize.core.pysize_fs_tree import pysize_tree
7 from pysize.core.compute_size import size_observable
9 # We don't want the building of a tree to block the GUI. A possible
10 # solution is to periodically call gtk.main_iteration_do() during the
11 # building. Unfortunately, this introduces reentrance issues when an
12 # event trigger the building of another tree.
14 # So we build all trees in a single separate thread. This additional
15 # thread never touches the GUI. So when the GUI wants an updated tree
16 # it calls threaded_pysize_tree.schedule(), and when the thread finishes
17 # the tree it wakes the observer that will update the GUI.
19 # As the thread must not touch the GUI, every gtk manipulation must be made
20 # through a gobject.idle_add(lambda: ...).
22 # Yeah, we are using threads
23 gobject.threads_init()
25 # The only aim of this exception is to unwind the stack in order
26 # to abort the current building, and quickly procede to the next
27 # one.
28 class AbortThisTree(Exception):
29 pass
31 class threaded_pysize_tree(object):
32 def __init__(self):
33 self.completion = observable()
34 self.queue = Queue(0)
35 size_observable.add_observer(self.size_observer)
36 self.thread = Thread(target=self.run_thread)
37 self.thread.setDaemon(True)
38 self.thread.start()
40 def schedule(self, *args, **kwargs):
41 self.queue.put((args, kwargs))
43 # Called for every computed size(), that is, periodically during
44 # the building of a tree.
45 def size_observer(self, *args, **kwargs):
46 if not self.queue.empty():
47 # The GUI wants another tree, lets stop this one
48 raise AbortThisTree
50 def run_thread(self):
51 while True:
52 params = self.queue.get()
53 while not self.queue.empty():
54 # Get the last item
55 params = self.queue.get_nowait()
56 (args, kwargs) = params
57 gobject.idle_add(lambda: self.completion.fire_observers(None))
58 try:
59 tree = pysize_tree(*args, **kwargs)
60 except AbortThisTree:
61 continue
62 gobject.idle_add(lambda: self.completion.fire_observers(tree))