1 from threading
import Thread
2 from Queue
import Queue
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
28 class AbortThisTree(Exception):
31 class threaded_pysize_tree(object):
33 self
.completion
= observable()
35 size_observable
.add_observer(self
.size_observer
)
36 self
.thread
= Thread(target
=self
.run_thread
)
37 self
.thread
.setDaemon(True)
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
52 params
= self
.queue
.get()
53 while not self
.queue
.empty():
55 params
= self
.queue
.get_nowait()
57 gobject
.idle_add(lambda: self
.completion
.fire_observers(None))
59 tree
= pysize_tree(*args
, **kwargs
)
62 gobject
.idle_add(lambda: self
.completion
.fire_observers(tree
))