[pygtk] Waiting for a callback to run

Robert Schroll rschroll at gmail.com
Mon Feb 21 11:09:53 WST 2011


On 02/20/2011 03:08 PM, Stephen Langer wrote:
> This is what we do:
>
> class IdleBlockCallback:
>       def __init__(self, func, args=(), kwargs={}):
>            self.func = func
>            self.args = args
>            self.kwargs = kwargs
>            self.event = threading.Event()
>            self.result = None
>       def __call__(self):
>            gtk.gdk.threads_enter()
>            try:
>                 self.result = self.func(*self.args, **self.kwargs)
>            finally:
>                 gtk.gdk.flush()
>                 gtk.gdk.threads_leave()
>                 self.event.set()
>            return False              # don't repeat
>
> def runBlock(func, args=(), kwargs={}):
>       callbackobj = OOFIdleBlockCallback(func, args, kwargs)
>       callbackobj.event.clear()
>       gobject.idle_add(callbackobj, priority=gobject.PRIORITY_LOW)
>       callbackobj.event.wait()
>       return callbackobj.result
>

Thank you, thank you, thank you - this is exactly what I was looking 
for.  For some reason, I didn't think to look in Python's threading 
module.  Two questions:

1) Since all GTK stuff is happening in the mainloop thread, I'm only 
calling gobject.threads_init(), not gtk.gdk.threads_init() (as suggested 
here: http://library.gnome.org/devel/gtk-faq/stable/x499.html)  Am I 
correct in understanding that I don't need to call 
gtk.gdk.threads_enter() and _leave() in the callback?  (I've taken them 
out, and nothing seemed to break.)  What about the flush()?

2) I'd like to use this code in a project to be released under the BSD 
license.  Is that okay with you?

> Call runBlock on the worker thread.  Be sure that you're really on the worker thread, because if you call it on the main thread it will hang.

If I understand things correctly (unlikely), gobject.main_depth() will 
be greater than zero in the main loop thread and zero in the worker 
threads.  (At least if I only start the main loop in one thread.)  So 
I've written this function to ensure code is called in the main loop. 
Limited testing suggests it's working.

def run_in_main_loop(func, *args, **kwargs):
     if gobject.main_depth():
         # In the main loop already
         return func(*args, **kwargs)
     callbackobj = IdleBlockCallback(func, args, kwargs)
     callbackobj.event.clear()
     gobject.idle_add(callbackobj, priority=gobject.PRIORITY_LOW)
     callbackobj.event.wait()
     return callbackobj.result

Thanks again,
Robert


More information about the pygtk mailing list