
So here's what I don't understand: we make a non-blocking call to gtk+'s main loop
So far, so good.
(which makes a blocking call in a new OS thread).
With (the current version of) GHC's threaded RTS, there's only one OS thread involved until you spawn a second thread (with forkIO or forkOS).
So we get callbacks from gtk in this other thread, which is fine.
I'd expect you to get the callbacks in the same thread as the call-out, that is in your main thread (the same thread that was used to run the "main" action).
However if we launch any other Haskell threads that want to update the GUI in any way they need to make calls in the GUI OS thread. But the GUI OS thread is not in Haskell land at this point, it's blocked in a call to the gtk+ main loop.
Correct. GTK will need to help you a bit here for this to work. Many GUI toolkits offer a "post event to main event loop" function that may be called from any thread, at any time. You could use that to send a StablePtr (IO ()) to the GUI thread. You could also use a pipe to send that StablePtr to the GUI thread (I'm sure you can make GTK's event loop wait until a file descriptor is readable). I don't think that this machinery should take more than ten or twenty lines of code to implement. The absolute worst-case scenario involves registering a timer callback with GTK and regularily polling a Chan (IO ())... Cheers, Wolfgang