self._window.set_default_size(800, 300)
self._window.show_all()
+ self._loginSink = gtk_toolbox.threaded_stage(
+ gtk_toolbox.comap(
+ self.attempt_login,
+ gtk_toolbox.null_sink(),
+ )
+ )
+
backgroundSetup = threading.Thread(target=self._idle_setup)
backgroundSetup.setDaemon(True)
backgroundSetup.start()
self._errorDisplay.push_exception(e)
def _spawn_attempt_login(self, *args):
- backgroundLogin = threading.Thread(target=self.attempt_login, args=args)
- backgroundLogin.setDaemon(True)
- backgroundLogin.start()
+ self._loginSink.send(args)
def refresh_session(self):
"""
def contact_source_short_name(contactId):
return "Evo"
+ def clear_caches(self):
+ pass
+
@staticmethod
def factory_name():
return "Evolution"
self._window = gtk_toolbox.find_parent_window(self._recentview)
self._phoneTypeSelector = PhoneTypeSelector(widgetTree, self._backend)
+ self._updateSink = gtk_toolbox.threaded_stage(
+ gtk_toolbox.comap(
+ self._idly_populate_recentview,
+ gtk_toolbox.null_sink(),
+ )
+ )
+
def enable(self):
assert self._backend.is_authed()
self._recentview.set_model(self._recentmodel)
def update(self, force = False):
if not force and self._isPopulated:
return
- backgroundPopulate = threading.Thread(target=self._idly_populate_recentview)
- backgroundPopulate.setDaemon(True)
- backgroundPopulate.start()
+ self._updateSink.send(())
def clear(self):
self._isPopulated = False
self._window = gtk_toolbox.find_parent_window(self._messageview)
self._phoneTypeSelector = PhoneTypeSelector(widgetTree, self._backend)
+ self._updateSink = gtk_toolbox.threaded_stage(
+ gtk_toolbox.comap(
+ self._idly_populate_messageview,
+ gtk_toolbox.null_sink(),
+ )
+ )
+
def enable(self):
assert self._backend.is_authed()
self._messageview.set_model(self._messagemodel)
def update(self, force = False):
if not force and self._isPopulated:
return
- backgroundPopulate = threading.Thread(target=self._idly_populate_messageview)
- backgroundPopulate.setDaemon(True)
- backgroundPopulate.start()
+ self._updateSink.send(())
def clear(self):
self._isPopulated = False
self._window = gtk_toolbox.find_parent_window(self._contactsview)
self._phoneTypeSelector = PhoneTypeSelector(widgetTree, self._backend)
+ self._updateSink = gtk_toolbox.threaded_stage(
+ gtk_toolbox.comap(
+ self._idly_populate_contactsview,
+ gtk_toolbox.null_sink(),
+ )
+ )
+
def enable(self):
assert self._backend.is_authed()
def update(self, force = False):
if not force and self._isPopulated:
return
- backgroundPopulate = threading.Thread(target=self._idly_populate_contactsview)
- backgroundPopulate.setDaemon(True)
- backgroundPopulate.start()
+ self._updateSink.send(())
def clear(self):
self._isPopulated = False
self._contactsmodel.clear()
-
- def clear_caches(self):
for factory in self._addressBookFactories:
factory.clear_caches()
self._addressBook.clear_caches()
import functools
import contextlib
import warnings
+import threading
+import Queue
import gobject
import gtk
return immediate_func
+def autostart(func):
+ """
+ >>> @autostart
+ ... def grep_sink(pattern):
+ ... print "Looking for %s" % pattern
+ ... while True:
+ ... line = yield
+ ... if pattern in line:
+ ... print line,
+ >>> g = grep_sink("python")
+ Looking for python
+ >>> g.send("Yeah but no but yeah but no")
+ >>> g.send("A series of tubes")
+ >>> g.send("python generators rock!")
+ python generators rock!
+ >>> g.close()
+ """
+
+ @functools.wraps(func)
+ def start(*args, **kwargs):
+ cr = func(*args, **kwargs)
+ cr.next()
+ return cr
+
+ return start
+
+
+@autostart
+def null_sink():
+ """
+ Good for uses like with cochain to pick up any slack
+ """
+ while True:
+ item = yield
+
+
+@autostart
+def comap(function, target):
+ """
+ >>> p = printer_sink()
+ >>> cm = comap(lambda x: x+1, p)
+ >>> cm.send(0)
+ 1
+ >>> cm.send(1.0)
+ 2.0
+ >>> cm.send(-2)
+ -1
+ >>> # cm.throw(RuntimeError, "Goodbye")
+ >>> # cm.send(0)
+ >>> # cm.send(1.0)
+ >>> # cm.close()
+ """
+ while True:
+ try:
+ item = yield
+ mappedItem = function(*item)
+ target.send(mappedItem)
+ except StandardError, e:
+ target.throw(e.__class__, e.message)
+
+
+@autostart
+def queue_sink(queue):
+ """
+ >>> q = Queue.Queue()
+ >>> qs = queue_sink(q)
+ >>> qs.send("Hello")
+ >>> qs.send("World")
+ >>> qs.throw(RuntimeError, "Goodbye")
+ >>> qs.send("Meh")
+ >>> qs.close()
+ >>> print [i for i in _flush_queue(q)]
+ [(None, 'Hello'), (None, 'World'), (<type 'exceptions.RuntimeError'>, 'Goodbye'), (None, 'Meh'), (<type 'exceptions.GeneratorExit'>, None)]
+ """
+ while True:
+ try:
+ item = yield
+ queue.put((None, item))
+ except StandardError, e:
+ queue.put((e.__class__, e.message))
+ except GeneratorExit:
+ queue.put((GeneratorExit, None))
+ raise
+
+
+def decode_item(item, target):
+ if item[0] is None:
+ target.send(item[1])
+ return False
+ elif item[0] is GeneratorExit:
+ target.close()
+ return True
+ else:
+ target.throw(item[0], item[1])
+ return False
+
+
+def nonqueue_source(queue, target):
+ """
+ >>> q = Queue.Queue()
+ >>> for i in [
+ ... (None, 'Hello'),
+ ... (None, 'World'),
+ ... (GeneratorExit, None),
+ ... ]:
+ ... q.put(i)
+ >>> qs = queue_source(q, printer_sink())
+ Hello
+ """
+ isDone = False
+ while not isDone:
+ item = queue.get()
+ isDone = decode_item(item, target)
+ while not queue.empty():
+ queue.get_nowait()
+
+
+def threaded_stage(target, thread_factory = threading.Thread):
+ messages = Queue.Queue()
+
+ run_source = functools.partial(nonqueue_source, messages, target)
+ thread = thread_factory(target=run_source)
+ thread.setDaemon(True)
+ thread.start()
+
+ # Sink running in current thread
+ return queue_sink(messages)
+
+
class LoginWindow(object):
def __init__(self, widgetTree):