@@ -29,12 +29,17 @@ import Data.Traversable
2929import qualified Data.Text as T
3030import Data.Text.Encoding
3131import Data.Monoid ((<>))
32+import Data.IORef
33+import Data.Maybe
34+
35+newtype EventTriggerRef t m a = EventTriggerRef { unEventTriggerRef :: Ref m (Maybe (EventTrigger t a)) }
3236
3337data GuiEnv t h x
3438 = GuiEnv { _guiEnvDocument :: !HTMLDocument
3539 , _guiEnvPostGui :: !(h () -> IO ())
3640 , _guiEnvRunWithActions :: !([DSum (EventTrigger t)] -> h ())
3741 , _guiEnvWebView :: !(WebViewSingleton x)
42+ , _guiEnvFollowupEvents :: Ref h [DSum (EventTriggerRef t h)]
3843 }
3944
4045--TODO: Poorly named
@@ -102,10 +107,14 @@ instance HasWebView m => HasWebView (Widget t m) where
102107instance (MonadRef h, Ref h ~ Ref m, MonadRef m) => HasPostGui t h (Gui t h x m) where
103108 askPostGui = Gui $ view guiEnvPostGui
104109 askRunWithActions = Gui $ view guiEnvRunWithActions
110+ scheduleFollowup r a = Gui $ do
111+ followupEventsRef <- view guiEnvFollowupEvents
112+ modifyRef' followupEventsRef $ ((EventTriggerRef r :=> a) :)
105113
106114instance HasPostGui t h m => HasPostGui t h (Widget t m) where
107115 askPostGui = lift askPostGui
108116 askRunWithActions = lift askRunWithActions
117+ scheduleFollowup r a = lift $ scheduleFollowup r a
109118
110119type WidgetInternal t m a = ReaderT WidgetEnv (StateT (WidgetState t m) m) a
111120
@@ -215,10 +224,12 @@ instance HasPostGui t h m => HasPostGui t (WithWebView x h) (WithWebView x m) wh
215224 askRunWithActions = do
216225 runWithActions <- lift askRunWithActions
217226 return $ lift . runWithActions
227+ scheduleFollowup r a = lift $ scheduleFollowup r a
218228
219229instance HasPostGui Spider SpiderHost SpiderHost where
220230 askPostGui = return $ \h -> liftIO $ runSpiderHost h
221231 askRunWithActions = return fireEvents
232+ scheduleFollowup _ _ = liftIO $ putStrLn "scheduleFollowup{Spider,SpiderHost,SpiderHost}: not implemented"
222233
223234instance MonadTrans (WithWebView x) where
224235 lift = WithWebView . lift
@@ -248,11 +259,25 @@ attachWidget :: forall e x a. (IsHTMLElement e) => e -> WebViewSingleton x -> Wi
248259attachWidget rootElement wv w = runSpiderHost $ flip runWithWebView wv $ do --TODO: It seems to re-run this handler if the URL changes, even if it's only the fragment
249260 Just doc <- liftM (fmap castToHTMLDocument) $ liftIO $ nodeGetOwnerDocument rootElement
250261 frames <- liftIO newChan
251− rec let guiEnv = GuiEnv doc (writeChan frames . runSpiderHost . flip runWithWebView wv) runWithActions wv :: GuiEnv Spider (WithWebView x SpiderHost) x
262+ followupEvents <- liftIO $ newIORef []
263+ rec let guiEnv = GuiEnv doc (writeChan frames . runSpiderHost . flip runWithWebView wv) runWithActions wv followupEvents :: GuiEnv Spider (WithWebView x SpiderHost) x
252264 runWithActions dm = do
253265 voidActionNeeded <- fireEventsAndRead dm $ do
254266 sequence =<< readEvent voidActionHandle
255− runHostFrame $ runGui (sequence_ voidActionNeeded) guiEnv
267+ case voidActionNeeded of
268+ Nothing -> return ()
269+ Just va -> do
270+ runHostFrame $ runGui va guiEnv
271+ doFollowup
272+ doFollowup = do
273+ fe <- liftIO $ atomicModifyIORef followupEvents $ \x -> ([], x)
274+ fe' <- forM fe $ \(EventTriggerRef r :=> a) -> do
275+ mt <- readRef r
276+ case mt of
277+ Nothing -> return Nothing
278+ Just t -> return $ Just (t :=> a)
279+ let fe'' = catMaybes fe'
280+ when (not $ null fe'') $ runWithActions fe''
256281 Just df <- liftIO $ documentCreateDocumentFragment doc
257282 (result, voidAction) <- runHostFrame $ flip runGui guiEnv $ do
258283 (r, postBuild, va) <- runWidget df w
@@ -262,6 +287,7 @@ attachWidget rootElement wv w = runSpiderHost $ flip runWithWebView wv $ do --TO
262287 _ <- liftIO $ nodeAppendChild rootElement $ Just df
263288 voidActionHandle <- subscribeEvent voidAction --TODO: Should be unnecessary
264289 --postGUISync seems to leak memory on GHC (unknown on GHCJS)
290+ doFollowup -- This must go after voidActionHandle is subscribed; otherwise, a loop results
265291 _ <- liftIO $ forkIO $ forever $ postGUISync =<< readChan frames -- postGUISync is necessary to prevent segfaults in GTK, which is not thread-safe
266292 return result
267293