
Also Sprach Brandon S. Allbery KF8NH:
You can make it "global" without using unsafePerformIO: Set up a ReaderT MyState IO and run the program inside it, after initializing your MyState with appropriate IORefs. You need to lift gtk2hs functions, and callbacks have to be wrapped to push them back up into the ReaderT:
curState <- ask lift $ widget `on` buttonPressEvent $ runReaderT curState . myCallback
The reason you want a ReaderT instead of a StateT is that any state not accessed via an IORef can't be propagated between the mainline code and callbacks, so you want something that is forced to be read-only after initialization except via an IORef stored within it.
Aside: I've suggested at times that gtk2hs use class MonadIO instead of type IO, which would make explicit lifting (and I think "dropping") unnecessary. I never made a formal enhancement suggestion though; I should do so.
Thanks for your very helpful answer :-) I ended up passing a state object around in functions and then porting it back to use the Monad (damn deadlines, always in the way of sound programming.) If the GTK2hs people made this a bit easier, it would surely help. I'll look into the possibilities myself, too. Thanks again, Aleks